CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
-PROJECT(capi-trackrenderer-tv)
+PROJECT(libtrackrenderer)
SET(description "new multimedia player, object-oriented model")
-SET(PC_NAME "capi-trackrenderer-tv")
+SET(PC_NAME "libtrackrenderer")
SET(PC_LDFLAGS "-ltrackrenderer")
SET(INC_DIR ${PROJECT_SOURCE_DIR}/include/)
SET(CMAKE_INSTALL_PREFIX /usr)
SET(PREFIX ${CMAKE_INSTALL_PREFIX})
-CONFIGURE_FILE(capi-trackrenderer-tv.pc.in
- capi-trackrenderer-tv.pc
+CONFIGURE_FILE(libtrackrenderer.pc.in
+ libtrackrenderer.pc
@ONLY
)
-INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/capi-trackrenderer-tv.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/libtrackrenderer.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
ADD_SUBDIRECTORY(src)
-OPTION(TRACKRENDERER_BUILD_UT "Build capi-trackrenderer-tv ut codes" OFF)
+OPTION(TRACKRENDERER_BUILD_UT "Build libtrackrenderer ut codes" OFF)
IF(TRACKRENDERER_BUILD_UT)
ADD_SUBDIRECTORY(ut)
ENDIF(TRACKRENDERER_BUILD_UT)
--- /dev/null
+Copyright (c) Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Apache License, Version 2.
+Please, see the LICENSE file for Apache License terms and conditions.
+++ /dev/null
-#* * PlusPlayer * * #\r
- PlusPlayer is a new multimedia player object-oriented designed.\r
-\r
-## Notice\r
- * 18_Plusplayer\r
- - Confluence\r
- - SW High Level Design doc.\r
-\r
-## Goals ##\r
- * Improve maintainability / extensibility / reusability\r
- - object oriented design\r
- - separate the modules into high-variation part and low-variation part\r
- - decoupling between each streaming services\r
- * Simplification\r
- - simplified pipeline , creates static pipeline\r
- * Easy to upgrade\r
- - support downloadable features (planned)\r
-\r
-## Architecture Design ##\r
- * PlusPlayer consists of TypeFinder / TrackSource / TrackRenderer / DefaultPlayer objects.\r
- * TypeFinder\r
- - Probing source type by inspecting probing data\r
- - use gstreamer typefinder plugin\r
- * TrackSource\r
- - Fetching data from server , demuxing , controling demuxed packet buffers\r
- - a pipeline consists of `src - typefinder - demuxer - multiqueue - inputselector - fakesink`\r
- - plz refer to `${plusplayer_workspace}/docs/dot/plusplayer_src_start.png`\r
- * TrackRenderer\r
- - maintains a pipeline consists of `appsrc - omx - sink` elements\r
- - plz refer to `${plusplayer_workspace}/docs/dot/plusplayer_renderer_start.png`\r
- * Class diagram\r
- * ${plusplayer_workspace}/docs/class_diagram.plantuml\r
- * or you can directly download it from [class_diagram.plantuml]\r
-\r
-## Development ##\r
- * GitHub Project :\r
- * All the milestones / activities (Codes , CodeReview , Design , Issues , etc) are being uploaded here\r
- * Codereview on Github\r
- - Each Developers should fork master branch and work on their own forked project.\r
- - developer should submit pull-request to apply their changes\r
- * all developers must sync their forked project with the latest master prior to sumit pull-request. so that we can avoid merge conflicts.\r
- - everyone can join the codereviews\r
- * the coding style follows Google C++ coding style guide. refer to [CODING STYLE](### coding-style)\r
- * Test Driven Development (use gtest - plusplayer_ut -for their implementation and verifications)\r
-\r
-#### GTest guide ####\r
- * To write Unit test case for PlusPlayer\r
- * docs/gtest_guide.md\r
- * Check Reference section of above link for more detailed documents.\r
- * example\r
- ```\r
- sh-3.2# plusplayer_ut --gtest_filter="AvPlusPlayerTest.play"\r
- ```\r
-\r
-#### Coding Rule Check ####\r
- * check your coding style using **cpplint.py** before uploading your codes\r
- > e.g) $ **cpplint.py** cpp_style_test.cpp\r
- * Or check your coding style and fix your codes automatically using **clang-format**\r
- > e.g) $ **clang-format-3.4** cpp_style_test.cpp -style=google **-i**\r
-\r
-#### Build ####\r
- > 1. Clone or Download plusplayer package.\r
- > 2. $ gbs -c ~/gbsconf/gbs_3_0.conf build -A armv7l --include-all --clean -B ~/GBS_ROOT_PLUSPLAYER\r
-\r
-#### Understanding the codes ####\r
- to understand PlusPlayer concept quickly\r
- plz refer to\r
- - ${plusplayer_workspace}/ut/porting/webapi-plugins-avplay/src/avplusplayer.cc/h\r
- - ${plusplayer_workspace}/src/player/defaultplayer.cpp/h\r
- - ${plusplayer_workspace}/docs/class_diagram.txt\r
-\r
-#### CODING STYLE ####\r
- 'Google C++ Style Guide' based coding.\r
- > Translated(Korean)\r
- > Original(English)\r
- > [[CodingRule.md]]\r
+++ /dev/null
-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
+++ /dev/null
-\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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-## **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
+++ /dev/null
-@startuml\r
-@enduml
\ No newline at end of file
+++ /dev/null
-@startuml\r
-\r
-' to be updated soon\r
-' this is test\r
-\r
-@enduml
\ No newline at end of file
+++ /dev/null
-@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
+++ /dev/null
-**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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-# **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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
+++ /dev/null
-@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
*/
#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
void* buffer;
+ void* caps;
#else
GstBuffer* buffer;
+ GstCaps* caps;
#endif
} TrackRendererDecoderInputBuffer;
/**
- * @file
+ * @file
* @brief Managed display related data structures and enums used by
* trackrenderer apis.
* @interfacetype Platform
} TrackRendererCropArea;
-/**
- * @brief Region of render rectangle
- */
-typedef struct _TrackRendererRenderRect {
- /**
- * @description x value of render rectangle
- */
- int x;
-
- /**
- * @description y value of render rectangle
- */
- int y;
-
- /**
- * @description width of render rectangle
- */
- int w;
-
- /**
- * @description height of render rectangle
- */
- int h;
-} TrackRendererRenderRect;
-
/**
* @brief Enumerations for the display type
*/
kTrackRendererDrmTypeSecuremedia,
kTrackRendererDrmTypeSdrm,
kTrackRendererDrmTypeWidevineCdm,
+ kTrackRendererDrmTypeClearkey,
kTrackRendererDrmTypeDrmMax
};
-/**
- * @file
- * @brief The event for playback.
- * @interfacetype Platform
- * @platform_porting_interface
- * @privlevel None-privilege
- * @privilege None
- * @product TV, AV, B2B
- * @version 2.0
- * @SDK_Support N
- * @remark This is a group of C style event related enum and structure.
- * @see N/A
- *
- * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
- * PROPRIETARY/CONFIDENTIAL
- * This software is the confidential and proprietary
- * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
- * not disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into with
- * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
- * suitability of the software, either express or implied, including but not
- * limited to the implied warranties of merchantability, fitness for a
- * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
- * damages suffered by licensee as a result of using, modifying or distributing
- * this software or its derivatives.
- */
-
-#ifndef __PLUSPLAYER_TRACKRENDERER_CAPI_EVENT_H__
-#define __PLUSPLAYER_TRACKRENDERER_CAPI_EVENT_H__
-
-#include <cstdint>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // __PLUSPLAYER_TRACKRENDERER_CAPI_EVENT_H__
+/**\r
+ * @file\r
+ * @brief The event for playback.\r
+ * @interfacetype Platform\r
+ * @platform_porting_interface \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) 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_TRACKRENDERER_CAPI_EVENT_H__\r
+#define __PLUSPLAYER_TRACKRENDERER_CAPI_EVENT_H__\r
+\r
+#include <cstdint>\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#ifdef __cplusplus\r
+} // extern "C"\r
+#endif\r
+\r
+#endif // __PLUSPLAYER_TRACKRENDERER_CAPI_EVENT_H__\r
int value;
} TrackRendererIniProperty;
+/**
+ * @brief Plusplayer ini element map pair.
+ */
+typedef struct _TrackRendererIniElement {
+ /**
+ * @description ini property.
+ */
+ const char* key;
+
+ /**
+ * @description ini property value.
+ */
+ const char* value;
+} TrackRendererIniElement;
+
#ifdef __cplusplus
} // extern "C"
#endif
+++ /dev/null
-/**
- * @file
- * @brief managed error related enum used by trackrenderer apis.
- * @interfacetype Platform
- * @privlevel None-privilege
- * @privilege None
- * @product TV, AV, B2B
- * @version 3.0
- * @SDK_Support N
- * @remark This is a group of C style error releted enum.
- * @see All error enum values will be converted to this managed error
- * types.
- *
- * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
- * PROPRIETARY/CONFIDENTIAL
- * This software is the confidential and proprietary
- * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
- * not disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into with
- * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
- * suitability of the software, either express or implied, including but not
- * limited to the implied warranties of merchantability, fitness for a
- * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
- * damages suffered by licensee as a result of using, modifying or distributing
- * this software or its derivatives.
- */
-
-#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_LATENCY_H__
-#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_LATENCY_H__
-
-#include "tizen.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-/**
- * @brief Enumerations for the error type
- */
-enum TrackRendererCatchUpSpeed {
- kTrackRendererCatchUpSpeedNone,
- kTrackRendererCatchUpSpeedSlow,
- kTrackRendererCatchUpSpeedNormal,
- kTrackRendererCatchUpSpeedFast
-};
-
-enum TrackRendererLatencyStatus {
- kTrackRendererLatencyStatusLow,
- kTrackRendererLatencyStatusMid,
- kTrackRendererLatencyStatusHigh
-};
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_LATENCY_H__
* @description Subtitle format.
*/
const char* subtitle_format;
+
+ /**
+ * @description Stream format.
+ */
+ const char* stream_format;
+
+ /**
+ * @description Alignment.
+ */
+ const char* alignment;
+
+ /**
+ * @description Original media type.
+ */
+ const char* original_media_type;
+
+ /**
+ * @description Protection system.
+ */
+ const char* protection_system;
+
} TrackRendererTrack;
/**
+++ /dev/null
-/**
- * @file track_capi.h
- * @brief trackrenderer internally used api c version
- * @interfacetype Module
- * @platform_porting_interface
- * @privlevel None-privilege
- * @privilege None
- * @product TV, AV, B2B
- * @version 3.0
- * @SDK_Support N
- * @remark This is track api set for trackrenderer implemented as C
- * style to avoid binary compatibility issues.
- *
- * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
- * PROPRIETARY/CONFIDENTIAL
- * This software is the confidential and proprietary
- * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
- * not disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into with
- * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
- * suitability of the software, either express or implied, including but not
- * limited to the implied warranties of merchantability, fitness for a
- * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
- * damages suffered by licensee as a result of using, modifying or distributing
- * this software or its derivatives.
- */
-
-#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACK_CAPI_H__
-#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACK_CAPI_H__
-
-#include "trackrenderer_capi/track.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief Enumerations for types of track handle
- */
-typedef void* TrackRendererTrackHandle;
-
-/**
- * @brief Enumerations for types of endianness
- */
-enum TrackRendererTrackEndianness {
- kTrackRendererTrackEndiannessLittle, /**< Little Endian */
- kTrackRendererTrackEndiannessBig, /**< Big Endian */
-};
-
-/**
- * @brief Enumerations for types of signedness
- */
-enum TrackRendererTrackSignedness {
- kTrackRendererTrackSignednessSigned, /**< Signed */
- kTrackRendererTrackSignednessUnsigned, /**< Unsigned */
-};
-
-/**
- * @brief Enumerations for types of activation
- */
-enum TrackRendererTrackActivation {
- kTrackRendererTrackActivationActive, /**< Active */
- kTrackRendererTrackActivationDeactive, /**< Deactive */
-};
-
-/**
- * @brief Enumerations for types of decoder
- */
-enum TrackRendererTrackDecoderType {
- kTrackRendererTrackDecoderTypeHwOnly, /**< H/W Decoder */
- kTrackRendererTrackDecoderTypeSwOnly, /**< S/W Decoder */
-};
-
-/**
- * @brief [Video/Audio/Subtitle] Create empty track handle.
- * @param [out] handle : trackrenderer track handle ptr
- * @param [in] type : one of track type for track handle
- * @param [in] index : track index
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if track handle is created successfully.
- Otherwise -1 if handle is nullptr or memory allocation failure.
- * @retval 0 on success
- * @retval -1 on failure
- * @see TrackRendererTrackType
- */
-int trackrenderer_track_create(TrackRendererTrackHandle* handle,
- const TrackRendererTrackType type,
- const int index);
-
-/**
- * @brief [Video/Audio/Subtitle] Destroy track handle.
- * @param [in] handle : trackrenderer track handle ptr to destroy
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if track handle is destroyed successfully.
- Otherwise -1 if handle is nullptr.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_destroy(TrackRendererTrackHandle handle);
-
-/**
- * @brief [Video/Audio/Subtitle] Set track activated. If application
- * doesn't call this api, the track will be deactivated by
- * default.
- * @param [in] handle : trackrenderer track handle ptr to set activation
- * @param [in] activation : activation value
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the activation of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr.
- * @retval 0 on success
- * @retval -1 on failure
- * @see TrackRendererTrackActivation
- */
-int trackrenderer_track_set_activation(
- TrackRendererTrackHandle handle,
- const TrackRendererTrackActivation activation);
-
-/**
- * @brief [Video/Audio/Subtitle] Set mimetype for track
- * @param [in] handle : trackrenderer track handle ptr to set mimetype
- * @param [in] mimetype : mimetype with null terminated string
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the mimetype of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_set_mimetype(TrackRendererTrackHandle handle,
- const char* mimetype);
-
-/**
- * @brief [Video/Audio/Subtitle] Set streamtype for track
- * @param [in] handle : trackrenderer track handle ptr to set streamtype
- * @param [in] streamtype : streamtype with null terminated string
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the streamtype of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_set_streamtype(TrackRendererTrackHandle handle,
- const char* streamtype);
-
-/**
- * @brief [Video/Audio] Set codec data for track
- * @param [in] handle : trackrenderer track handle ptr to set codec data
- * @param [in] codec_data : bytes array of codec_data
- * @param [in] codec_data_len : size of the codec_data
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the codec data of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr,
- * codec_data_len is over 1MB or the type of the track handle is
- * different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_set_codec_data(TrackRendererTrackHandle handle,
- const char* codec_data,
- const int codec_data_len);
-
-/**
- * @brief [Video/Audio] Set decoder type. default value is
- * kTrackRendererTrackDecoderTypeHwOnly
- * @param [in] handle : trackrenderer track handle ptr to set decoder
- * type
- * @param [in] type : type of decoder (h/w or s/w)
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the decoder type of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- * @see TrackRendererTrackDecoderType
- */
-int trackrenderer_track_set_decoder_type(
- TrackRendererTrackHandle handle, const TrackRendererTrackDecoderType type);
-
-/**
- * @brief [Video] Set resolution for video track
- * @param [in] handle : trackrenderer track handle ptr to set resolution
- * @param [in] width : width of video frame
- * @param [in] height : height of video frame
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the resolution of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_video_set_resolution(TrackRendererTrackHandle handle,
- const int width, const int height);
-
-/**
- * @brief [Video] Set max resolution for video track
- * @param [in] handle : trackrenderer track handle ptr to set max
- * resolution
- * @param [in] width : maximum width of video frame
- * @param [in] height : maximum height of video frame
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the max resolution of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_video_set_max_resolution(
- TrackRendererTrackHandle handle, const int width, const int height);
-
-/**
- * @brief [Video] Set framerate for video track
- * @param [in] handle : trackrenderer track handle ptr to set framerate
- * @param [in] num : numerator of video sequence
- * @param [in] den : denominator of video sequence
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the framerate of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_video_set_framerate(TrackRendererTrackHandle handle,
- const int num, const int den);
-
-/**
- * @brief [Video] Set video codec tag for video track
- * @param [in] handle : trackrenderer track handle ptr to set video codec
- * tag
- * @param [in] codec_tag : codec tag with null terminated string
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the codec tag of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_video_set_codec_tag(TrackRendererTrackHandle handle,
- const char* codec_tag);
-
-/**
- * @brief [Video] Set version for video track
- * @param [in] handle : trackrenderer track handle ptr to set version
- * @param [in] version : version of video codec
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the version of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_video_set_version(TrackRendererTrackHandle handle,
- const int version);
-
-/**
- * @brief [Audio] Set sample rate for audio track
- * @param [in] handle : trackrenderer track handle ptr to set sample rate
- * @param [in] sample_rate : sample rate of audio stream
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the sample rate of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_sample_rate(TrackRendererTrackHandle handle,
- const int sample_rate);
-
-/**
- * @brief [Audio] Set sample format for audio track
- * @param [in] handle : trackrenderer track handle ptr to set sample
- * format
- * @param [in] sample_format : sample format of audio stream
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the sample format of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_sample_format(TrackRendererTrackHandle handle,
- const int sample_format);
-
-/**
- * @brief [Audio] Set channels for audio track
- * @param [in] handle : trackrenderer track handle ptr to set channels
- * @param [in] channels : channels of audio stream
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the channels of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_channels(TrackRendererTrackHandle handle,
- const int channels);
-
-/**
- * @brief [Audio] Set version for audio track
- * @param [in] handle : trackrenderer track handle ptr to set version
- * @param [in] version : version of audio codec
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the version of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_version(TrackRendererTrackHandle handle,
- const int version);
-
-/**
- * @brief [Audio] Set layer for audio track
- * @param [in] handle : trackrenderer track handle ptr to set layer
- * @param [in] layer : layer of audio stream
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the layer of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_layer(TrackRendererTrackHandle handle,
- const int layer);
-
-/**
- * @brief [Audio] Set bits per sample (bps) for audio track
- * @param [in] handle : trackrenderer track handle ptr to set bps
- * @param [in] bits_per_sample : bits per sample of audio stream
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the bits per sample of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_bits_per_sample(
- TrackRendererTrackHandle handle, const int bits_per_sample);
-
-/**
- * @brief [Audio] Set block align for audio track
- * @param [in] handle : trackrenderer track handle ptr to set block align
- * @param [in] block_align : block align of audio stream
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the block align of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_block_align(TrackRendererTrackHandle handle,
- const int block_align);
-
-/**
- * @brief [Audio] Set bitrate for audio track
- * @param [in] handle : trackrenderer track handle ptr to set bitrate
- * @param [in] bitrate : bitrate of audio stream
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the bitrate of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_bitrate(TrackRendererTrackHandle handle,
- const int bitrate);
-
-/**
- * @brief [Audio] Set layout for audio track
- * @param [in] handle : trackrenderer track handle ptr to set layout
- * @param [in] layout : layout of audio stream with null terminated
- * string
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the layout of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_layout(TrackRendererTrackHandle handle,
- const char* layout);
-
-/**
- * @brief [Audio] Set flavor for audio track
- * @param [in] handle : trackrenderer track handle ptr to set flavor
- * @param [in] flavor : flavor of audio stream
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the flavor of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_flavor(TrackRendererTrackHandle handle,
- const int flavor);
-
-/**
- * @brief [Audio] Set endianness for audio track
- * @param [in] handle : trackrenderer track handle ptr to set endianness
- * @param [in] endianness : endianness of audio stream
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the endianness of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- * @see TrackRendererTrackEndianness
- */
-int trackrenderer_track_audio_set_endianness(
- TrackRendererTrackHandle handle,
- const TrackRendererTrackEndianness endianness);
-
-/**
- * @brief [Audio] Set signedness for audio track
- * @param [in] handle : trackrenderer track handle ptr to set signedness
- * @param [in] signedness : signedness of audio stream
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the signedness of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_signedness(
- TrackRendererTrackHandle handle,
- const TrackRendererTrackSignedness signedness);
-
-/**
- * @brief [Audio] Set codec tag for audio track
- * @param [in] handle : trackrenderer track handle ptr to set codec tag
- * @param [in] codec_tag : codec tag with null terminated string
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the codec tag of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_audio_set_codec_tag(TrackRendererTrackHandle handle,
- const char* codec_tag);
-
-/**
- * @brief [Subtitle] Set language code for subtitle track
- * @param [in] handle : trackrenderer track handle ptr to set language
- * code
- * @param [in] language_code : language code with null terminated string
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the language code of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_subtitle_set_language_code(
- TrackRendererTrackHandle handle, const char* language_code);
-
-/**
- * @brief [Subtitle] Set subtitle format for subtitle track
- * @param [in] handle : trackrenderer track handle ptr to set subtitle
- * format
- * @param [in] subtitle_format : subtitle format with null terminated
- * string
- * @pre None
- * @post None
- * @exception None
- * @return Returns 0 if the subtitle format of the track handle is set
- * successfully. Otherwise -1 if handle is nullptr or the type of
- * the track handle is different.
- * @retval 0 on success
- * @retval -1 on failure
- */
-int trackrenderer_track_subtitle_set_subtitle_format(
- TrackRendererTrackHandle handle, const char* subtitle_format);
-
-#ifdef __cplusplus
-}
-#endif
-#endif // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACKRENDERER_TRACK_CAPI_H__
\ No newline at end of file
* @file trackrenderer_capi.h
* @brief Plusplayer trackrenderer api c version.
* @interfacetype Platform
- * @platform_porting_interface
* @privlevel None-privilege
* @privilege None
* @product TV, AV, B2B
#include "trackrenderer_capi/error.h"
//#include "trackrenderer_capi/event.h"
#include "trackrenderer_capi/iniproperty.h"
-#include "trackrenderer_capi/latency.h"
#include "trackrenderer_capi/state.h"
#include "trackrenderer_capi/submitstatus.h"
#include "trackrenderer_capi/track.h"
} TrackRendererAppInfo;
/**
- * @brief Event message
+ * @brief
*/
typedef struct {
/**
- * @description event message data
- * eg) kTrackRendererEventTypeResolutionChanged : "1920x1080"
+ * @description
*/
char* data;
/**
- * @description the length of event message data
+ * @description
*/
uint64_t len;
} TrackrendererEventMsg;
/**
- * @brief Enumerations for the audio easing type
- * @version 3.0
- */
-enum TrackRendererAudioEasingType {
- /**
- * @description audio easing function type is linear
- */
- kTrackRendererAudioEasingLinear = 0,
- /**
- * @description audio easing function type is incubic
- */
- kTrackRendererAudioEasingIncubic,
- /**
- * @description audio easing function type is outcubic
- */
- kTrackRendererAudioEasingOutcubic,
- /**
- * @description audio easing function type is none
- */
- kTrackRendererAudioEasingNone
-};
-
-/**
- * @brief audio easing information struct
- * @version 3.0
- */
-typedef struct _TrackRendererAudioEasingInfo {
- /**
- * @description audio easing target volume
- */
- uint32_t target_volume;
- /**
- * @description audio easing duration, in millisecond
- */
- uint32_t duration;
- /**
- * @description audio easing type
- */
- TrackRendererAudioEasingType type;
-} TrackRendererAudioEasingInfo;
-
-/**
- * @brief Enumerations for the resource types
- * @version 3.0
- */
-enum TrackRendererRscType {
- kTrackRendererRscTypeVideoRenderer,
-};
-
-/**
- * @brief Enumerations for event message types
+ * @brief
*/
enum TrackRendererEventType {
kTrackRendererEventTypeNone,
kTrackRendererEventTypeResolutionChanged,
};
-/**
- * @brief Enumerations for advanced picture quality types
- */
-enum TrackRendererAdvPictureQualityType {
- kTrackRendererAdvPictureQualityTypeVideoCall,
- kTrackRendererAdvPictureQualityTypeUsbCamera,
-};
-
-/**
- * @brief Enumerations for resource allocate policy
- */
-enum TrackRendererRscAllocPolicy {
- kTrackRendererRscAllocExclusive,
- kTrackRendererRscAllocConditional,
-};
-
-/**
- * @brief the numerator/denominator value
- * @version 3.2
- */
-typedef struct _TrackRendererRational {
- int num;
- int den;
-} TrackRendererRational;
-
typedef void* TrackRendererHandle;
/**
* @description If there is an error, this function will post
* trackrenderer_set_error_cb in advance.
* @post User will handle the posted error according to error code.
* @see trackrenderer_set_error_cb()
- * @see trackrenderer_error_msg_cb() if a detailed error message is
- * required
*/
typedef void (*trackrenderer_error_cb)(const TrackRendererErrorType error_code,
void* userdata);
-/**
- * @description If there is an error, this function will post
- * error message with error code and detailed infomation.
- * @param [in] error_code : enum TrackRendererErrorType\n
- * @param [in] error_msg : detailed error message including info related
- * to codec,demuxer,network status, etc.
- * @param [in] userdata : userdata of trackrenderer_error_cb
- * callback function.
- * @pre The callback function should be set by
- * trackrenderer_set_error_msg_cb in advance.
- * @post User will handle the posted error according to error code.
- * @see trackrenderer_set_error_msg_cb()
- * @see trackrenderer_error_cb() if only simple error code is required
- */
-typedef void (*trackrenderer_error_msg_cb)(
- const TrackRendererErrorType error_code, char* error_msg, void* userdata);
-
/**
* @description If there is a resource conflict, this function will notice
* that there is resource conflict. Then trackrenderer can
typedef void (*trackrenderer_eos_cb)(void* userdata);
/**
- * @description When a specific event occurs, this function will be called to
- * notify it.
- * @param [in] event_type : event type that occured
- * @param [in] msg_data : event information
+ * @description When resolution is changed, this function will be
+ * called to notify that resolution has been changed changed.
+ * @param [in] event_type : Resolution change event type.
+ * @param [in] msg_data : Resolution info.
* @param [in] userdata : userdata of trackrenderer_event_cb callback
* function.
* @pre The callback function should be set by
* trackrenderer_set_event_cb, in advance.
- * @post User can get the information of the event that occured
+ * @post User can handle fuctionality referencing resolution info.
* @see trackrenderer_set_event_cb()
*/
typedef void (*trackrenderer_event_cb)(const TrackRendererEventType event_type,
const uint64_t offset,
void* userdata);
-/**
- * @description When trackrenderer finish to decode video buffer,
- * this is called want to get an useful tbm point form the tbm
- * list.
- * @param [in] ptr : pointer set to get tbm address \n
- * [in] is_scale_change : param indicate whether scale resolution
- * changed \n
- * @pre The callback function should be set by
- * trackrenderer_set_media_packet_video_tbmptr_cb, in advance.
- * @post User can get an useful tbm surface ptr
- * @version 3.2
- * @see trackrenderer_set_media_packet_video_tbmptr_cb()
- */
-typedef void (*trackrenderer_media_packet_video_tbmptr_cb)(void** ptr,
- bool is_scale_change,
- void* userdata);
-
/**
* @description When trackrenderer finish to decode video buffer,
* this is called, then user can get the decoded video buffer
typedef void (*trackrenderer_media_packet_video_decoded_cb)(
const TrackRendererDecodedVideoPacket* packet, void* userdata);
-/**
- * @description If the latency status of the video stream changes, this
- * function will be called.
- * @param [in] latency_status : the video latency status \n
- * [in] userdata : userdata of trackrenderer_latency_status_cb
- * function.
- * @pre The callback function should be set by
- * trackrenderer_set_video_latency_status_cb, in advance.
- * @post User can decide the next operation after the latency status
- * changes.
- * @see trackrenderer_set_video_latency_status_cb()
- */
-typedef void (*trackrenderer_video_latency_status_cb)(
- const TrackRendererLatencyStatus video_latency_status, void* userdata);
-
-/**
- * @description If the latency status of the audio stream changes, this
- * function will be called.
- * @param [in] latency_status : the audio latency status \n
- * [in] userdata : userdata of trackrenderer_latency_status_cb
- * function.
- * @pre The callback function should be set by
- * trackrenderer_set_audio_latency_status_cb, in advance.
- * @post User can decide the next operation after the latency status
- * changes.
- * @see trackrenderer_set_audio_latency_status_cb()
- */
-typedef void (*trackrenderer_audio_latency_status_cb)(
- const TrackRendererLatencyStatus audio_latency_status, void* userdata);
-
-/**
- * @description If high latency occurs, this function will be called.
- * @param [in] userdata : userdata of trackrenderer_video_high_latency_cb
- * function.
- * @pre The callback function should be set by
- * trackrenderer_set_video_high_latency_cb, in advance.
- * @post User can decide the next operation after video high latency
- * occurs.
- * @see trackrenderer_set_video_high_latency_cb()
- */
-typedef void (*trackrenderer_video_high_latency_cb)(void* userdata);
-
-/**
- * @description If high latency occurs, this function will be called.
- * @param [in] userdata : userdata of trackrenderer_audio_high_latency_cb
- * function.
- * @pre The callback function should be set by
- * trackrenderer_set_audio_high_latency_cb, in advance.
- * @post User can decide the next operation after audio high latency
- * occurs.
- * @see trackrenderer_set_audio_high_latency_cb()
- */
-typedef void (*trackrenderer_audio_high_latency_cb)(void* userdata);
-
-/**
- * @description If ResourceCenter sends video start request to a player when
- * it's required, this function will be called.
- * @param [in] userdata : userdata of
- * trackrenderer_multiview_start_video_cb callback function.
- * @pre The callback function should be set by
- * trackrenderer_set_multiview_start_video_cb in advance.
- * @post User will activate video stream.
- * @see trackrenderer_set_multiview_start_video_cb()
- */
-typedef void (*trackrenderer_multiview_start_video_cb)(void* userdata);
-
-/**
- * @description If ResourceCenter sends video stop request to a player when
- * it's required, this function will be called.
- * @param [in] userdata : userdata of
- * trackrenderer_multiview_stop_video_cb callback function.
- * @pre The callback function should be set by
- * trackrenderer_set_multiview_stop_video_cb in advance.
- * @post User will deactivate video stream.
- * @see trackrenderer_set_multiview_stop_video_cb()
- */
-typedef void (*trackrenderer_multiview_stop_video_cb)(void* userdata);
-
/**
* @brief return libtrackrenderer.so lib version as string
* @param None
* @return version info - major.minor.micro - as string
- * @code
- * //your logic
- * const char* version;
- * version = trackrenderer_get_version();
- * //your logic
- * @endcode
* @pre None
* @post None
* @exception None
* @brief return libtrackrenderer.so lib version as constant int.
* @param None
* @return version info - major.minor.micro - as unsigned int
- * @code
- * //your logic
- * uint32_t version = 0;
- * version = trackrenderer_get_version_int();
- * //your logic
- * @endcode
* @pre None
* @post None
* @exception None
* related job ex) display setting, decoding, rendering, etc..
* @param [out] handle : Get trackrenderer handle ptr.
* @return 0 on success, otherwise -1 failed.
- * @code
- * TrackRendererHandle handle = nullptr;
- * trackrenderer_create(&handle);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre None
* @post None
* @exception None
* @description Remove and dealloc trackrenderer object and handle.
* @param [in] handle : trackrenderer handle
* @return 0 on success, otherwise -1 failed.
- * @code
- * refer to the sample code of trackrenderer_create()
- * @endcode
* @pre None
* @post None
* @exception None
- * @see trackrenderer_create()
*/
int trackrenderer_destroy(TrackRendererHandle handle);
* @return Return 0 if no problem.
* Otherewise -1 if the trackrenderer is not even set up.
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post The contents is playing.
* @exception None
* @code
- * //prepare trackrenderer hanle
- * trackrenderer_start(handle);
- * //your logic
- * trackrenderer_pause(handle);
- * //your logic
- * trackrenderer_resume(handle);
- * //your logic
- * trackrenderer_stop(handle);
+ * TrackRendererHandle handle = nullptr;
+ * trackrenderer_create(&handle)
+ * TrackRendererDisplayType type = kTrackRendererDisplayTypeOverlay;
+ * ...
+ * ...
+ * TrackRendererTrack tracks[] = {videotrack, audiotrack};
+ * int tracksize = 2;
+ * trackrenderer_set_track(handle, tracks, tracksize);
+ * trackrenderer_prepare(handle);
+ * trackrenderer_start(handle);
* @endcode
* @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare()
*/
int trackrenderer_start(TrackRendererHandle handle);
* @return Return 0 if the trackrenderer is not even setup or release the
* resource successfully.
* Otherwise -1.
- * @code
- * refer to the sample code of trackrenderer_start()
- * @endcode
* @pre After trackrenderer object is created, this can be called.
+ * trackrenderer_create()
* @post Trackrenderer release the decoder and display resource.
* @exception None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_start()
*/
int trackrenderer_stop(TrackRendererHandle handle);
* @return Return 0 if all valid tracks playback is successfully prepared,
* succeed to update display 1 decoded frame media contents.
* Otherwise -1.
- * @code
- * trackrenderer_create(&handle);
- * //set tracks if needed
- * trackrenderer_prepare(handle);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre Active tracks informations for playing need to be set up.
+ * trackrenderer_create()
+ * trackrenderer_set_track()
* The media contents data must be delivered as mush as
* trackrenderer can parse data type.
* @post 1 decoded frame media contents is displayed. The necessary TV
* resource is prepared to use.
* @exception None
* @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_set_track()
*/
int trackrenderer_prepare(TrackRendererHandle handle);
* @return Return 0 if trakrenderer is successfully paused.
* Oterwise return -1 if trackrenderer already release the
* resource.
- * @code
- * refer to the sample code of trackrenderer_start()
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post The trackrenderer pause playback and displaying 1 decoded frame
* data.
* @exception None
* @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_start()
*/
int trackrenderer_pause(TrackRendererHandle handle);
* @return Returen 0 if trackrenderer is successfully resume media
* contents.
* Otherwise -1.
- * @code
- * refer to the sample code of trackrenderer_start()
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post The contents is playing.
* @exception None
* @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_start() \n
- * trackrenderer_pause()
*/
int trackrenderer_resume(TrackRendererHandle handle);
* subtitle and successcully set the track info to trackrenderer.
* Otherwise -1 if there is not any active tracks or already set
* tracks info.
- * @code
- * TrackRendererHandle handle = nullptr;
- * trackrenderer_create(&handle)
- * TrackRendererTrack tracks[] = {videotrack, audiotrack};
- * int tracksize = 2;
- * trackrenderer_set_track(handle, tracks, tracksize);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre Get active tracks list for playing.
* @post Set up left of other properties to trackrenderer with using
* trackrenderer_prepare().
* @exception None
* @remark None
- * @see trackrenderer_create()
*/
int trackrenderer_set_track(TrackRendererHandle handle,
const TrackRendererTrack* track, const int size);
* @param [in] handle : trackrenderer handle ptr.
* @param [in] properties : Setting properties got from property file.
* @param [in] property_size : Number of properties for parsing.
- * @code
- * trackrenderer_create(&handle)
- * TrackRendererIniProperty properties[2];
- * properties[0].key = "use_new_hls_mpegts_demuxer";
- * properties[0].value = true;
- * properties[1].key = "use_new_dash_tiny_demuxer";
- * properties[1].value = false;
- * trackrenderer_set_ini_property(handle, properties, 2)
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre Load property file and get informations.
* @post Trackrenderer set the parsed properties.
* @exception None
* @remark None
- * @see trackrenderer_create()
*/
void trackrenderer_set_ini_property(TrackRendererHandle handle,
TrackRendererIniProperty* properties,
int property_size);
+/**
+ * @brief Set elements to trackrenderer.
+ * @description Parsing element informations from loaded config file and set values
+ * to trackrenderer.
+ * @param [in] handle : trackrenderer handle ptr.
+ * @param [in] elements : Setting elements got from config file.
+ * @param [in] element_size : Number of config elements for parsing.
+ * @pre Load property file and get element informations.
+ * @post Trackrenderer set the parsed elements.
+ * @exception None
+ * @remark None
+ */
+void trackrenderer_set_ini_element(TrackRendererHandle handle,
+ TrackRendererIniElement* elements,
+ int element_size);
+
/**
* @brief Seek trackrenderer playback position, asynchronously.
* @description In this function, trackrenderer seek playback position to
* Otherwise -1 if the trackrenderer is not even setup,
* trackrenderer fail to seek playback position or fail to set
* playback rate.
- * @code
- * static void SeekDoneCb(UserData userdata) {
- * //do something you want when seek done
- * }
- * static void SeekDataCb(const TrackRendererTrackType type,
- * const unsigned long long offset, UserData userdata) {
- * //do something you want when trackrenderer is ready
- * to get new seeked position segment data
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_seekdone_cb(handle, SeekDoneCb, nullptr);
- * trackrenderer_set_seekdata_cb(handle, SeekDataCb, nullptr);
- * trackrenderer_prepare(handle);
- * trackrenderer_start(handle);
- * //your logic
- * trackrenderer_seek(handle,10,1.0);
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post Release the buffered data and start buffering seeked position
* segment data.
* @exception None
* called when seek operation is finished.
* The accecptable playback rate is different for each streaming
* source type.
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_start() \n
- * trackrenderer_set_seekdone_cb()
*/
int trackrenderer_seek(TrackRendererHandle handle,
unsigned long long time_millisecond,
* the stream in milliseconds
* @param [in] playback_rate : For trick play playback rate.
* @param [in] audio_mute : audio is mute on/off when seek to target
- * position.
+ * position.
* @return Return 0 if he trackrenderer can seek the position or set
* playback rate successfully. Playback rate 0 is not accecptable
* eventhough return value is 0.
* Otherwise -1 if the trackrenderer is not even setup,
* trackrenderer fail to seek playback position or fail to set
* playback rate.
- * @code
- * //prepare trackrenderer hanle
- * //your logic
- * trackrenderer_start(handle);
- * //your logic
- * trackrenderer_seek2(handle,10,1.0,true);
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post Release the buffered data and start buffering seeked position
* segment data.
* @exception None
* called when seek operation is finished.
* The accecptable playback rate is different for each streaming
* source type.
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_start()
*/
int trackrenderer_seek2(TrackRendererHandle handle,
unsigned long long time_millisecond,
/**
* @brief Set trackrenderer playback rate, asynchronously.
* @description In this function, trackrenderer set playback rate and audio
- * mute on/off.
+ * mute on/off.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] playback_rate : For trick play playback rate.
* @param [in] audio_mute : For trick play audio mute on/off, true: mute
- * on, false: mute off.
+ * on, false: mute off.
* @return Return 0 if he trackrenderer can set playback rate
- * successfully. Playback rate 0 is not accecptable
+ * successfully. Playback rate 0 is not accecptable
* eventhough return value is 0.
* Otherwise -1 if the trackrenderer is not even setup,
* trackrenderer fail to set playback rate.
- * @code
- * //prepare trackrenderer hanle
- * //your logic
- * trackrenderer_set_playback_rate(handle, 2.0, true);
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post Release the buffered data and start buffering current playing
* position
* @exception None
- * @version 2.0
+ * @version 2.0
* @remark Setting playback rate is asynchronous operation.
* The accecptable playback rate is different for each streaming
* source type.
- * @see trackrenderer_create() \n
- * trackrenderer_prepare()
*/
int trackrenderer_set_playback_rate(TrackRendererHandle handle,
double playback_rate, bool audio_mute);
* @return Return 0 if trackrenderer successfully get currently rendering
* contents position.
* Otherwise -1.
- * @code
- * //prepare trackrenderer hanle
- * //your logic
- * uint64_t time_millisecond = 0;
- * trackrenderer_get_playing_time(handle, &time_millisecond));
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post None
* @exception None.
* @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare()
*/
int trackrenderer_get_playing_time(TrackRendererHandle handle,
- unsigned long long* time_millisecond);
+ uint64_t* time_millisecond);
/**
* @brief Get dropped frame counts in videosink
* @description In this function trackrenderer get currently dropped frames in
- * sink.
+ * sink.
* @param [in] handle : trackrenderer handle ptr.
* @param [out] counts : dropped counts
* @return Return 0 if trackrenderer successfully get frame counts.
* Otherwise -1.
- * @code
- * //prepare trackrenderer hanle
- * //your logic
- * uint64_t count = 0;
- * trackrenderer_get_dropped_frames(handle,static_cast<void*>(&count)));
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
- * @post None
- * @exception None.
- * @version 2.0
- * @remark None
- * @see trackrenderer_create() \n
+ * trackrenderer_create()
* trackrenderer_prepare()
- */
-int trackrenderer_get_dropped_frames(TrackRendererHandle handle, void* counts);
-
-/**
- * @brief Get dropped frame counts for catchup in video/audio sink
- * @description In this function trackrenderer get dropped frames for catchup
- * in sink.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] type : the type of the track
- * @param [out] counts : dropped counts
- * @return Return 0 if trackrenderer successfully get frame counts.
- * Otherwise -1.
- * @code
- * //prepare trackrenderer hanle
- * //your logic
- * uint64_t dropped_video_frames = 0;
- * trackrenderer_get_dropped_frames_for_catchup(handle,
- * TrackRendererTrackType::kTrackRendererTrackTypeVideo,
- * static_cast<void*>(&dropped_video_frames)));
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
- * @pre The trackrenderer must be at least created and set up.
* @post None
* @exception None.
- * @version 3.0
+ * @version 2.0
* @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare()
*/
-int trackrenderer_get_dropped_frames_for_catchup(TrackRendererHandle handle,
- TrackRendererTrackType type,
- void* counts);
+int trackrenderer_get_dropped_frames(TrackRendererHandle handle, void* counts);
/**
* @brief Flush buffers for a trackrenderer.
* @description In this function trackrenderer will flush data in
- * appsrc,decoder,sink.
+ * appsrc,decoder,sink.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] type : type of track which need to be flush.
* @return Return 0 if flushing buffer for a track successfully.
* Otherwise -1.
- * @code
- * static void FlushDoneCb(UserData userdata) {
- * //do something you want to do when flush done
- * }
-
- * trackrenderer_create(&handle);
- * trackrenderer_flushdone_cb(handle, FlushDoneCb, nullptr);
- * trackrenderer_prepare(handle);
- * //your logic
- * trackrenderer_flush(handle, kTrackRendererTrackTypeAudio);
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post None
* @exception None.
- * @version 2.0
+ * @version 2.0
* @remark trackrenderer_flushdone_cb() is called when flush operation is
- * fininshed
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_flushdone_cb()
+ * fininshed
*/
int trackrenderer_flush(TrackRendererHandle handle,
TrackRendererTrackType type);
* the TV resources.
* Otherwise -1 if the trackrenderer is not even set up or fail to
* release the resources.
- * @code
- * //prepare trackrenderer hanle
- * //your logic
- * trackrenderer_deactivate(handle, kTrackRendererTrackTypeVideo)
- * //your logic
- * trackrenderer_activate(handle,
- * kTrackRendererTrackTypeVideo,nullptr));
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post trackrenderer_activate() should be called if new data stream
* need to be inserted and get new TV resource for decoding and
* rendering.
* @exception None
* @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare()
+ *
*/
int trackrenderer_deactivate(TrackRendererHandle handle,
TrackRendererTrackType type);
* @return Return 0 if trackrenderer is successfully rebuilt with using
* new data stream. Otherwise -1 if the trackrenderer is not even
* set up or fail to get resources.
- * @code
- * refer to the sample code of trackrenderer_deactivate()
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post None
* @exception None
* @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_deactivate()
*/
int trackrenderer_activate(TrackRendererHandle handle,
TrackRendererTrackType type,
* or the EOS data.
* Otherwise -1 if the trackrenderer is not even set up, queue is
* already full or the data is unusable.
- * @code
- * static void BufferStatusCb(const TrackRendererTrackType type,
- * const TrackRendererBufferStatus status,UserData userdata) {
- * if (type == kTrackRendererTrackTypeAudio) {
- * if (status == kTrackRendererBufferStatusUnderrun)
- * // do something when feed Audio is possible
- * else
- * //do something when feed Audio is impossible
- * } else if(type == kTrackRendererTrackTypeVideo) {
- * if (status == kTrackRendererBufferStatusUnderrun)
- * //do something when feed Video is possible
- * else
- * //do something when feed Video is impossible
- * } else if(type == kTrackRendererTrackTypeSubtitle) {
- * if (status == kTrackRendererBufferStatusUnderrun)
- * //do something when feed Subtitle is possible
- * else
- * //do something when feed Subtitle is impossible
- * }
- * }
- * void FeedPacket(const TrackRendererHandle& handle,
- * const TrackRendererDecoderInputBufferPtr& buffer,...) {
- * //your logic
- * SubmitStatus status=kTrackRendererSubmitStatusNotPrepared;
- * trackrenderer_submit_packet(handle, buffer.get(),&status);
- * //your logic
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_bufferstatus_cb(handle,BufferStatusCb,nullptr);
- * trackrenderer_prepare(handle);
- * //your logic
- * //execute FeedPacket() when feed is possible.
- * (call a new thread to do this)
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post If EOS is submitted to buffer, trackrenderer_eos_cb will be
* called.
* @exception None
* @remark The buffered tracksource data is submitted to trackrenderer by
* feeder.
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_set_bufferstatus_cb()
+ *
+ *
+ * this is data copy
*/
int trackrenderer_submit_packet(TrackRendererHandle handle,
TrackRendererDecoderInputBuffer* data,
* @param [in] data : the data user want to add to the trackrenderer
* buffer
* @param [out] retval : the result of submition.
- * @code
- refer to the sample code of trackrenderer_submit_packet()
- * @endcode
* @return Return 0 if trackrenderer successfully add the buffer to queue
* or the EOS data.
* Otherwise -1 if the trackrenderer is not even set up, queue is
* already full or the data is unusable.
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post If EOS is submitted to buffer, trackrenderer_eos_cb will be
* called.
* @exception None
* @remark The buffered tracksource data is submitted to trackrenderer by
* feeder.
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_set_bufferstatus_cb()
+ *
+ * this is data move
*/
int trackrenderer_submit_packet2(TrackRendererHandle handle,
TrackRendererDecoderInputBuffer* data,
* process itself.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] drm_property : drm property
- * @code
- * trackrenderer_create(&handle);
- * TrackRendererDrmProperty trackrenderer_drm_property{
- * kTrackRendererDrmTypePlayready,
- * 0, 1, nullptr, nullptr};
- * trackrenderer_set_drm(handle,&trackrenderer_drm_property);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created.
+ * @pre None
* @post None
* @exception None
* @remark Set drm property directly
- * @see trackrenderer_create()
*/
void trackrenderer_set_drm(TrackRendererHandle handle,
TrackRendererDrmProperty* drm_property);
* process itself.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] type : which type of track drm license was acquired
- * @code
- * //prepare trackrenderer hanle
- * //your logic
- * trackrenderer_drm_license_acquired_done(handle,
- * kTrackRendererTrackTypeMax);
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post None
* @exception None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare()
*/
void trackrenderer_drm_license_acquired_done(TrackRendererHandle handle,
TrackRendererTrackType type);
+/**
+ * @brief Set drm key
+ * @description
+ * @param [in] handle : trackrenderer handle ptr.
+ * @param [in] type : track type(audio, video, subtitle)
+ * @param [in] key : drm clearkey
+ * @pre None
+ * @exception None
+ */
+void trackrenderer_set_drm_license_key(TrackRendererHandle handle,
+ TrackRendererTrackType type,
+ const char * key);
+
/**
* @brief Set the video display mode.
* @description In this function set how display shows. If the
* @return Return 0 if rendering mode is successfully applied or stored
* for future displaying.
* Otherwise -1 if the trackrenderer is not even setup.
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_display_mode(
- * handle, kTrackRendererDisplayModeOriginSize));
- * //your logic
- * TrackRendererDisplayMode display_mode =
- * static_cast<TrackRendererDisplayMode>(-1);
- * trackrenderer_get_display_mode(handle, &display_mode);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* @post None
* @exception None
* @remark None
- * @see trackrenderer_create()
*/
int trackrenderer_set_display_mode(TrackRendererHandle handle,
TrackRendererDisplayMode mode);
* @brief Set the video display rotate angle.
* @description In this function will set the video display rotate. If the
* trackrenderer is not prepared to update the display rotate yet,
- * the trackrenderer stored the rotate and update it after
+ * the
+ * trackrenderer stored the rotate and update it after
* trackrenderer is ready to update display.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] rotate : display rotate angle
* @return Return 0 if rendering mode is successfully applied or stored
* for future displaying.
* Otherwise -1 if the trackrenderer is not even setup.
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_display_rotate(handle,kTrackRendererDisplayRotate90);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* @post None
* @exception None
- * @version 2.0
+ * @version 2.0
* @remark None
- * @see trackrenderer_create()
*/
int trackrenderer_set_display_rotate(TrackRendererHandle handle,
TrackRendererDisplayRotate rotate);
* @param [out] rotate : store the display rotate angle
* @return Return 0 if get rotate value success.
* Otherwise -1 if the trackrenderer is not even setup.
- * @code
- * trackrenderer_create(&handle);
- * //your logic
- * TrackRendererDisplayRotate gtype =
- * kTrackRendererDisplayRotateNone;
- * rackrenderer_get_display_rotate(handle, >ype);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* @post None
* @exception None
- * @version 2.0
+ * @version 2.0
* @remark None
- * @see trackrenderer_create()
*/
int trackrenderer_get_display_rotate(TrackRendererHandle handle,
TrackRendererDisplayRotate* rotate);
* @return Return 0 if rendering properties are successfully applied for
* displaying contents or stored for future displaying.
* Otherwise -1 if the trackrenderer is not even setup.
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_display_surface(handle,
- * kTrackRendererDisplayTypeOverlay, 3, 100, 100, 100, 100);
- * //your logic
- * TrackRendererDisplayType type = kTrackRendererDisplayTypeNone;
- * TrackRendererGeometry area = {-1, -1, -1, -1};
- * trackrenderer_get_display(handle, &type, &area);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* @post None
* @exception None
* @remark None
- * @see trackrenderer_create()
*/
int trackrenderer_set_display_surface(TrackRendererHandle handle,
TrackRendererDisplayType type,
* @return Return 0 if rendering object is successfully applied for
* displaying contents or stored for future displaying.
* Otherwise -1 if the trackrenderer is not even setup.
- * @code
- * trackrenderer_create(&handle);
- * Environment* env = new Environment();
- * TrackRendererDisplayType type =
- * kTrackRendererDisplayTypeOverlay;
- * trackrenderer_set_display(handle,type,env->Window());
- * //your logic
- * delete env;
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* @post None
* @exception None
* @remark None
- * @see trackrenderer_create()
*/
int trackrenderer_set_display(TrackRendererHandle handle,
TrackRendererDisplayType type, void* obj);
* applied for displaying contents or stored for future
* displaying.
* Otherwise -1 if the trackrenderer is not even setup.
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_display_ecore_wl2_window(
- * handle,kTrackRendererDisplayTypeOverlay,NULL,
- * 0,0,1920,1080));
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* @post None
* @exception None
* @remark None
- * @see trackrenderer_create()
*/
int trackrenderer_set_display_ecore_wl2_window(TrackRendererHandle handle,
TrackRendererDisplayType type,
void* ecore_wl2_window, int x,
int y, int w, int h);
-/**
- * @brief Set the video display properties.
- * @description In this function set rendering object and rendering
- * locations. If the trackrenderer is not prepared to update the
- * display yet, the trackrenderer stored the rendering object
- * properties and update display after trackrenderer is ready to
- * update display.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] type : display type
- * @param [in] ecore_wl2_subsurface : ecore wl subsurface handle to
- * display window.
- * @param [in] x : x param of display window
- * @param [in] y : y param of display window
- * @param [in] w : width of display window
- * @param [in] h : height of display window
- * @return Return 0 if rendering oejct and properties are successfully
- * applied for displaying contents or stored for future
- * displaying.
- * Otherwise -1 if the trackrenderer is not even setup.
- * @pre The trackrenderer must be at least created.
- * @post None
- * @exception None
- * @version 3.1
- * @remark None
- * @see trackrenderer_create()
- */
-int trackrenderer_set_display_ecore_wl2_subsurface(
- TrackRendererHandle handle, TrackRendererDisplayType type,
- void* ecore_wl2_subsurface, int x, int y, int w, int h);
/**
* @brief Set the ROI(Region Of Interest) area of display
* @return Return 0 if rendering range is successfully set or
* rendering range is stored for future displaying.
* Otherwise -1 if the trackrenderer is not even setup.
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_display_mode(
- * handle, kTrackRendererDisplayModeDstRoi));
- * TrackRendererGeometry roi = {0, 0, 1920, 1080};
- * trackrenderer_set_display_roi(handle, &roi);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* The display mode should be set to
* kTrackRendererDisplayModeDstRoi.
+ * trackrenderer_set_display_mode()
* @post None
* @exception None
* @remark The minimum value of width and height are 1.
- * @see trackrenderer_create() \n
- * trackrenderer_set_display_mode()
*/
int trackrenderer_set_display_roi(TrackRendererHandle handle,
TrackRendererGeometry* roi);
/**
- * @brief Set the Crop Area(Region Of Src ratio) area of display.
- * @param [in] handle : esplusplayer handle.
- * @param [in] crop: x y label , height, width crop ratio in src video area.
- * @return @c true on success, otherwise @c false.
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_display_mode(
- * handle, kTrackRendererDisplayModeDstRoi));
- * TrackRendererCropArea roi = {0.2, 0.2, 0.5, 0.5};
- * trackrenderer_set_video_roi(handle, &roi));
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created and
- * The player state can be all of #esplusplayer_state except
- * #ESPLUSPLAYER_STATE_NONE.
- * @post None
- * @exception None
- * @version 2.0
- * @remark The minimum value of input are 0,maximun value is 1.
- * @see trackrenderer_create() \n
- * esplusplayer_set_display() \n
- * esplusplayer_set_display_visible()
- */
-int trackrenderer_set_video_roi(TrackRendererHandle handle,
- TrackRendererCropArea* crop);
-
-/**
- * @brief Resize the render rectangle(the max region that video can be
- * displayed).
+ * @brief Set the Crop Area(Region Of Src ratio) area of display.
* @param [in] handle : esplusplayer handle.
- * @param [in] rect: render rectangle.
+ * @param [in] crop: x y label , height, width crop ratio in src video area.
* @return @c true on success, otherwise @c false.
- * @pre This should be called after trackrenderer_set_display() \n
- * trackrenderer_set_display_surface() \n
- * trackrenderer_set_display_ecore_wl2_window() \n
- * trackrenderer_set_display_ecore_wl2_subsurface
+ * @pre The player state can be all of #esplusplayer_state except
+ * #ESPLUSPLAYER_STATE_NONE. \n
* @post None
* @exception None
- * @version 3.2
- * @remark The minimum value of width and height are 1.
+ * @version 2.0
+ * @remark The minimum value of input are 0,maximun value is 1.
* @see esplusplayer_set_display() \n
- * trackrenderer_set_display_surface() \n
- * trackrenderer_set_display_ecore_wl2_window() \n
- * trackrenderer_set_display_ecore_wl2_subsurface
+ * esplusplayer_set_display_visible()
*/
-int trackrenderer_resize_render_rect(TrackRendererHandle handle,
- TrackRendererRenderRect* rect);
+int trackrenderer_set_video_roi(TrackRendererHandle handle,
+ TrackRendererCropArea* crop);
/**
* @brief Set on off the video display.
* @return Return 0 if visibility is updated or stored for future
* displaying.
* Otherwise -1 if the trackrenderer is not even setup.
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_display_visible(handle, true);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* @post None
* @exception None
* @remark None
* @see This is similar to trackrenderer_set_audio_mute() for audio
- * @see trackrenderer_create()
*/
int trackrenderer_set_display_visible(TrackRendererHandle handle,
bool is_visible);
* @param [in] handle : trackrenderer handle ptr.
* @param [out] type : display type
* @param [out] area : Roi Geometry
- * @code
- * please refer to the sample code of
- * trackrenderer_set_display_surface
- * @endcode
- * @pre The trackrenderer must be at least created.
+ * @pre None
* @post None
* @exception None
- * @see trackrenderer_create() \n
- * trackrenderer_set_display_surface()
*/
void trackrenderer_get_display(TrackRendererHandle handle,
TrackRendererDisplayType* type,
* contents.
* @param [in] handle : trackrenderer handle ptr.
* @param [out] mode : display mode
- * @code
- * please refer to the sample code of
- * trackrenderer_set_display_mode
- * @endcode
- * @pre The trackrenderer must be at least created.
+ * @pre None
* @post None
* @exception None
- * @see trackrenderer_create() \n
- * trackrenderer_set_display_mode()
*/
void trackrenderer_get_display_mode(TrackRendererHandle handle,
TrackRendererDisplayMode* mode);
* rendering resources using this app id.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] app_id : application id
- * @code
- * trackrenderer_create(&handle);
- * std::string app_id = "plusplayer-mapi";
- * trackrenderer_set_app_id(handle, app_id.c_str());
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created.
+ * @pre None
* @post None
* @exception None
- * @see trackrenderer_create()
*/
void trackrenderer_set_app_id(TrackRendererHandle handle, const char* app_id);
/**
- * @brief Set App id to player for resource manager
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] app_info : application id, version, type.
- * @return @c true on success, otherwise @c false.
- * @code
- * trackrenderer_create(&handle);
- * TrackRendererAppInfo app_info;
- * app_info.id = "plusplayer-mapi";
- * app_info.version = "";
- * app_info.type = "";
- * trackrenderer_set_app_info(handle, &app_info);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created.
- * @post None
- * @exception None
- * @version 2.0
- * @see trackrenderer_create()
+ * @brief Set App id to player for resource manager
+ * @param [in] handle : trackrenderer handle ptr.
+ * @param [in] app_info : application id, version, type.
+ * @return @c true on success, otherwise @c false.
+ * @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
+ * @post None
+ * @exception None
+ * @version 2.0
*/
void trackrenderer_set_app_info(TrackRendererHandle handle,
const TrackRendererAppInfo* app_info);
* @return Return 0 if audio mute successfully turn into or stored for
* future playing.
* Otherwise -1 failed if the trackrenderer not even set up.
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_audio_mute(handle, true);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* @post None
* @exception None
* @remark None
- * @see trackrenderer_create()
+ * @see This is similar to trackrenderer_set_display_visible() for
+ * video.
*/
int trackrenderer_set_audio_mute(TrackRendererHandle handle, bool is_mute);
/**
- * @brief Set trackrenderer video still mode
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] type : trackrenderer still mode on, off or non
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_video_still_mode(handle,
- * kTrackRendererStillModeOn);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created.
- * @post None
- * @exception None
- * @see trackrenderer_create()
+ * (This is need to be checked wether it is using or not)
+ * @brief Set trackrenderer video still mode
+ * @param [in] handle : trackrenderer handle ptr.
+ * @param [in] type : trackrenderer still mode on, off or non
+ * @pre None
+ * @post None
+ * @exception None
*/
void trackrenderer_set_video_still_mode(TrackRendererHandle handle,
TrackRendererStillMode type);
* @brief Get trackrenderer current state
* @param [in] handle : trackrenderer handle ptr.
* @return Returns TrackRendererState.
- * @code
- * trackrenderer_create(&handle);
- * //your logic
- * TrackRendererState state = trackrenderer_get_state(handle);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created.
+ * @pre None
* @post None
* @exception None
- * @see trackrenderer_create()
*/
TrackRendererState trackrenderer_get_state(TrackRendererHandle handle);
* @param [in] attr_name : name of first property to set.
* @param [in] ... : value for the first property, followed optionally by
* more name/value pairs, followed by NULL.
- * @code
- * trackrenderer_create(&handle);
- * unsigned long long video_queue_size = 2 * 1024 * 1024; // 2MB
- * unsigned long long audio_queue_size = 100 * 1024; // 100KB
- * trackrenderer_set_attribute(handle,
- * "video-queue-max-byte", video_queue_byte,
- * "audio-queue-max-byte", audio_queue_byte,
- * NULL);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created.
+ * @pre None
* @post None
* @exception None
+ * @code
+ * unsigned long long video_queue_size = 2 * 1024 * 1024; // 2MB
+ * unsigned long long audio_queue_size = 100 * 1024; // 100KB
+ * trackrenderer_set_attribute(handle,
+ * "video-queue-max-byte", video_queue_byte,
+ * "audio-queue-max-byte", audio_queue_byte,
+ * NULL);
+ * @endcode
* @remark a name of attribute and a type of value must be paired. \n
* if you set wrong type of attribute, unknown error can be
* occured.\n if trackrenderer can't parse attr_name, assertion
* will be failed.
- * @see trackrenderer_create() \n
- * If you want to know what kinds of attribute are there, please
+ * @see If you want to know what kinds of attribute are there, please
* refer this link: \n
+ * http://wiki.vd.sec.samsung.net/display/plusplayer/TrackRenderer+Attribute
*/
void trackrenderer_set_attribute(TrackRendererHandle handle,
const char* attr_name, ...);
* @param [in] attr_name : name of first property to set.
* @param [in] ... : value for the first property, followed optionally by
* more name/value pairs, followed by NULL.
- * @code
- * trackrenderer_create(&handle);
- * unsigned long long video_current_byte;
- * unsigned long long audio_current_byte;
- * trackrenderer_get_attribute(handle,
- * "video-current-level-byte", &video_current_byte,
- * "audio-current-level-byte", &audio_current_byte,
- * NULL);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre None
* @post None
* @exception None
- * @version 2.0
+ * @version 2.0
+ * @code
+ * unsigned long long video_current_byte;
+ * unsigned long long audio_current_byte;
+ * trackrenderer_get_attribute(handle,
+ * "video-current-level-byte", &video_current_byte,
+ * "audio-current-level-byte", &audio_current_byte,
+ * NULL);
+ * @endcode
* @remark a name of attribute and a type of value must be paired. \n
* if you set wrong type of attribute, unknown error can be
* occured.\n if trackrenderer can't parse attr_name, assertion
* will be failed.
- * @see trackrenderer_create() \n
- * If you want to know what kinds of attribute are there, please
+ * @see If you want to know what kinds of attribute are there, please
* refer this link: \n
+ * http://wiki.vd.sec.samsung.net/display/plusplayer/TrackRenderer+Attribute
*/
void trackrenderer_get_attribute(TrackRendererHandle handle,
const char* attr_name, ...);
* @param [in] color_info : matroska color info
* @return Return 0 if no problem.
* Otherewise -1 if the trackrenderer is not even set up.
- * @code
- * //prepare trackrenderer hanle
- * //your logic
- * std::string color = "red";
- * trackrenderer_set_matroska_color_info(handle, color.c_str());
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
+ * trackrenderer_create()
+ * trackrenderer_prepare()
* @post None
* @exception None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare()
*/
int trackrenderer_set_matroska_color_info(TrackRendererHandle handle,
const char* color_info);
/**
- * @brief Set decoded video frame buffer type.
+ * @brief Set decoded video frame buffer type.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] type : one of the video decoded buffer type to set .
- * @pre The trackrenderer must be at least created, but before prepare
- * if type is not equal to be
- * kTrackRendererDecodedVideoFrameBufferScale.
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_video_frame_buffer_type(handle,
- * kTrackRendererDecodedVideoFrameBufferReference);
- * //your logic
- * trackrenderer_prepare(handle);
- * //your logic
- * @endcode
- * @pre The trackrenderer must be at least created and set up.
- * @post None
- * @exception None
- * @version 2.0
- * @see trackrenderer_create()
- */
-void trackrenderer_set_video_frame_buffer_type(
- TrackRendererHandle handle, TrackRendererDecodedVideoFrameBufferType type);
-
-/**
- * @brief Set the target scale resolution when decoded video frame buffer
- * type is scale
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] target_width : scale target width of video frame buffer.
- * @param [in] target_width : scale target height of video frame buffer.
- * @return Return 0 if no problem.
- * Otherewise -1 if the trackrenderer is not created.
* @pre The trackrenderer must be at least created but before prepare.
* trackrenderer_create()
- * @post None
- * @version 3.1
- * @exception None
- */
-int trackrenderer_set_video_frame_buffer_scale_resolution(
- TrackRendererHandle handle, uint32_t target_width, uint32_t target_height);
-
-/**
- * @brief Set the request frame rate of decoded video
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] request_framerate : the request frame rate of returned decoded video frame
- * The value of track_framerate and request_framerate should be one of the following sets:
- * track_framerate indicate the frame rate of input video stream
- * 1.A/(A-B) = X ,X means drop 1 frame every X frame
- * 2.Special cases,such as 24000/1000 -> 15000/1000
- * when request_framerate.num = 0, return none decoded video frame.
- * when request_framerate.num/request_framerate.den =
- * track_framerate.num/track_framerate.den, return all decoded
- * video frame.
- * when request_framerate.num/request_framerate.den <
- * track_framerate.num/track_framerate.den, drop some decoded
- * video frame.
- * @return Return 0 if no problem.
- * Otherewise -1 if the trackrenderer is not created or the value
- * of request_framerate is invalid .
- * @pre The trackrenderer must be at least created.
- * trackrenderer_create()
- * @post None
- * @version 3.3
- * @exception None
- * @remark Only works when decoded video frame buffer type is scale
+ * @post None
+ * @exception None
+ * @version 2.0
*/
-int trackrenderer_set_decoded_video_frame_rate(
- TrackRendererHandle handle, TrackRendererRational request_framerate);
+void trackrenderer_set_video_frame_buffer_type(
+ TrackRendererHandle handle, TrackRendererDecodedVideoFrameBufferType type);
/**
* @brief Set volume to trackrenderer
* @param [in] volume : volume level(0 ~ 100)
* @return Return 0 if no problem.
* Otherewise -1 if the trackrenderer is not created.
- * @code
- * trackrenderer_create(&handle);
- * int volume = 65;
- * trackrenderer_set_volume(handle, volume));
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* @post None
- * @version 2.0
+ * @version 2.0
* @exception None
- * @see trackrenderer_create()
*/
-
int trackrenderer_set_volume(TrackRendererHandle handle, const int volume);
/**
* @param [out] volume : volume ptr
* @return Return 0 if no problem.
* Otherewise -1 if the trackrenderer is not created.
- * @code
- * trackrenderer_create(&handle);
- * //your logic
- * int volume = 0;
- * trackrenderer_get_volume(handle, &volume));
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
* @pre The trackrenderer must be at least created.
+ * trackrenderer_create()
* @post None
- * @version 2.0
+ * @version 2.0
* @exception None
- * @see trackrenderer_create()
*/
int trackrenderer_get_volume(TrackRendererHandle handle, int* volume);
* video frame peek mode.
* @param [in] handle : trackrenderer handle ptr.
* @return Return 0 if no problem.
- * @code
- * //prepare trackrenderer hanle
- * //your logic
- * trackrenderer_render_video_frame(handle);
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
* @pre The trackrenderer must be at least created and set up.
* trackrenderer_create()
* trackrenderer_prepare() or after trackrenderer_seekdone_cb() is
* @post None
* @version 2.0
* @exception None
- * @remark esplusplayer_set_video_frame_peek_mode().
- * @see trackrenderer_create() \n
- * trackrenderer_prepare()
+ * @remark esplusplayer_set_video_frame_peek_mode().
*/
int trackrenderer_render_video_frame(TrackRendererHandle handle);
-/**
- * @brief Set catch up speed.
- * @description Set catch up speed for catch up. The properties will
- * be used to catch up with latency
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] level : catch up speed level.
- * @return Return 0 if there is no problem.
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_catch_up_speed(handle,
- * kTrackRendererCatchUpSpeedSlow);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
- * @post None
- * @exception None
- * @version 3.0
- * @remark None
- * @see trackrenderer_create()
- */
-int trackrenderer_set_catch_up_speed(TrackRendererHandle handle,
- const TrackRendererCatchUpSpeed level);
-/**
- * @brief Get current video latency status
- * @param [in] handle : trackrenderer handle ptr.
- * @param [out] status : current latency status.
- * @return Return 0 if there is no problem.
- * @code
- * trackrenderer_create(&handle);
- * //your logic
- * TrackRendererLatencyStatus status;
- * trackrenderer_get_video_latency_status(handle, &status)
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created and set up.
- * @post None
- * @exception None
- * @version 3.0
- * @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare()
-
- */
-int trackrenderer_get_video_latency_status(TrackRendererHandle handle,
- TrackRendererLatencyStatus* status);
-/**
- * @brief Get current audio latency status
- * @param [in] handle : trackrenderer handle ptr.
- * @param [out] status : current latency status.
- * @return Return 0 if there is no problem.
- * @code
- * refer to the sample code of
- * trackrenderer_get_video_latency_status()
- * @endcode
- * @pre The trackrenderer must be at least created and set up.
- * @post None
- * @exception None
- * @version 3.0
- * @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_get_video_latency_status()
- */
-int trackrenderer_get_audio_latency_status(TrackRendererHandle handle,
- TrackRendererLatencyStatus* status);
-
-/**
- * @brief Provided api for add an aifiter to the video pipeline.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] aifilter : aifilter plugin.
- * @return Return 0 if no problem.
- * @code
- * trackrenderer_create(&handle);
- * GstElement* aifilter =
- * gst_element_factory_make("aifilter_autozoom","auto_zoom");
- * if (aifilter != nullptr) {
- * g_object_set(G_OBJECT(aifilter),"detection-type",2,NULL);
- * g_object_set(G_OBJECT(aifilter),"is-enabled",TRUE,NULL);
- * }
- * trackrenderer_set_aifilter(handle,aifilter);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created.
- * @post None
- * @version 3.0
- * @exception None
- * @see trackrenderer_create()
- */
-int trackrenderer_set_aifilter(TrackRendererHandle handle, void* aifilter);
-
-/**
- * @brief Set mid latency threshold to trackrenderer
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] threshold : the threshold(number) of the video frames for
- * mid latency
- * @code
- * trackrenderer_create(&handle);
- * trackrenderer_set_audio_mid_latency_threshold(handle, 2);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @return Return 0 if there is no problem.
- * @pre The trackrenderer must be at least created
- * TrackRendererState should be kTrackRendererStateInit or
- * kTrackRendererStateWorking.
- * @post None
- * @exception None
- * @version 3.0
- * @remark None
- * @see trackrenderer_create()
- */
-int trackrenderer_set_video_mid_latency_threshold(TrackRendererHandle handle,
- const unsigned int threshold);
-
-/**
- * @brief Set mid latency threshold to trackrenderer
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] threshold : the threshold(number) of the audio frames for
- * mid latency
- * @code
- * refer the sample code of
- * trackrenderer_set_video_mid_latency_threshold()
- * @endcode
- * @return Return 0 if there is no problem.
- * @pre The trackrenderer must be at least created
- * trackrenderer_create()
- * TrackRendererState should be kTrackRendererStateInit or
- * kTrackRendererStateWorking.
- * @post None
- * @exception None
- * @version 3.0
- * @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_set_video_mid_latency_threshold()
- */
-int trackrenderer_set_audio_mid_latency_threshold(TrackRendererHandle handle,
- const unsigned int threshold);
-
-/**
- * @brief Set high latency threshold to trackrenderer
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] threshold : the threshold(number) of the video frames for
- * high latency
- * @return Return 0 if there is no problem.
- * @code
- * refer the sample code of
- * trackrenderer_set_video_mid_latency_threshold()
- * @endcode
- * @pre The trackrenderer must be at least created
- * trackrenderer_create()
- * TrackRendererState should be kTrackRendererStateInit or
- * kTrackRendererStateWorking.
- * @post None
- * @exception None
- * @version 3.0
- * @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_set_video_mid_latency_threshold()
- */
-int trackrenderer_set_video_high_latency_threshold(
- TrackRendererHandle handle, const unsigned int threshold);
-
-/**
- * @brief Set high latency threshold to trackrenderer
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] threshold : the threshold(number) of the audio frames for
- * high latency
- * @return Return 0 if there is no problem.
- * @code
- * refer the sample code of
- * trackrenderer_set_video_mid_latency_threshold()
- * @endcode
- * @pre The trackrenderer must be at least created
- * TrackRendererState should be kTrackRendererStateInit or
- * kTrackRendererStateWorking.
- * @post None
- * @exception None
- * @version 3.0
- * @remark None
- * @see trackrenderer_create() \n
- * trackrenderer_set_video_mid_latency_threshold()
- */
-int trackrenderer_set_audio_high_latency_threshold(
- TrackRendererHandle handle, const unsigned int threshold);
/* CALL back*/
* @param [in] callback : trackrenderer_error_cb function
* @param [in] userdata : userdata of trackrenderer_error_cb callback
* function.
- * @code
- * static void ErrorCb(const TrackRendererErrorType error_code,
- * UserData userdata) {
- * //Something you want to do when Receive error
- * printf("Receive error\n");
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_error_cb(handle, ErrorCb, nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
+ * @pre None
* @post When there is error event, trackrenderer_error_cb() is called.
* @exception None
* @remark trackrenderer_error_cb \n
* [in] error_code : enum TrackRendererErrorType\n
* [in] userdata : userdata of trackrenderer_error_cb
* callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_error_cb
*/
void trackrenderer_set_error_cb(TrackRendererHandle handle,
trackrenderer_error_cb callback,
void* userdata);
-/**
- * @brief Set error msg callback function.
- * @description If there is an error, the trackrenderer_error_cb will post
- * error message with error code and detailed infomation.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] callback : trackrenderer_error_msg_cb function
- * @param [in] userdata : userdata of trackrenderer_error_msg_cb callback
- * function.
- * @code
- * static void ErrorMsgCb(const TrackRendererErrorType error_code,
- * char* error_msg,UserData userdata) {
- * //Something you want to do when Receive error
- * printf("Receive error message: %s\n", error_msg);
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_error_msg_cb(handle, ErrorMsgCb, nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
- * @post When there is error event, trackrenderer_error_msg_cb() is
- * called.
- * @exception None
- * @version 3.0
- * @remark trackrenderer_error_msg_cb \n
- * [in] error_code : enum TrackRendererErrorType\n
- * [in] error_msg : detailed error message including info related
- * to codec,demuxer,network status, etc.
- * [in] userdata : userdata of trackrenderer_error_msg_cb
- * callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_error_msg_cb
- */
-void trackrenderer_set_error_msg_cb(TrackRendererHandle handle,
- trackrenderer_error_msg_cb callback,
- void* userdata);
-
/**
* @brief Set resource conflict callback funciton
* @description If there is resource conflict error, trackrender must release
* @param [in] callback : trackrenderer_resource_conflicted_cb ptr.
* @param [in] userdata : userdata of
* trackrenderer_resource_conflicted_cb callback function.
- * @code
- * static void ResourceConflictCb(UserData userdata) {
- * //Something you want to do when Resource Conflict
- * printf("Receive Resource Conflict message\n");
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_resourceconflict_cb(handle,
- * ResourceConflictCb, nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
+ * @pre None
* @post When there is resource conflict, the
* trackrenderer_resource_conflicted_cb will notify the resource
* conflict message to manage the resource.
* @remark trackrenderer_resource_conflicted_cb \n
* [in] userdata : userdata of
* trackrenderer_resource_conflicted_cb callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_resource_conflicted_cb
*/
void trackrenderer_set_resourceconflict_cb(
TrackRendererHandle handle, trackrenderer_resource_conflicted_cb callback,
void* userdata);
-/**
- * @brief Set video latency status callback function
- * @description If the latency status of the video stream changes, track
- * renderer must send the callback
- * to notify the application of the latency status.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] callback : trackrenderer_video_latency_status_cb ptr.
- * @param [in] userdata : userdata of
- * trackrenderer_video_latency_status_cb callback function.
- * @code
- * static void static void VideoLatencyStatusCb(
- * const TrackRendererLatencyStatus latency_status,
- * UserData userdata) {
- * //Something you want to do when VideoLatency Status change
- * printf("Receive VideoLatency Status change message\n");
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_video_latency_status_cb(handle,
- * VideoLatencyStatusCb, nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
- * @post When the latency status of the video stream changes,
- * trackrenderer_video_latency_status_cb will be sent.
- * @exception None
- * @version 3.0
- * @remark trackrenderer_video_latency_stuats_cb \n
- * [in] userdata : userdata of
- * trackrenderer_video_latency_status_cb callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_video_latency_stuats_cb
- */
-void trackrenderer_set_video_latency_status_cb(
- TrackRendererHandle handle, trackrenderer_video_latency_status_cb callback,
- void* userdata);
-
-/**
- * @brief Set audio latency status callback function
- * @description If the latency status of the audio stream changes, track
- * renderer must send the callback
- * to notify the application of the latency status.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] callback : trackrenderer_audio_latency_status_cb ptr.
- * @param [in] userdata : userdata of
- * trackrenderer_audio_latency_status_cb callback function.
- * @code
- * refer to the sample code of
- * trackrenderer_set_video_latency_status_cb()
- * @endcode
- * @pre The trackrenderer must be at least created
- * @post When the latency status of the audio stream
- * changes,trackrenderer_audio_latency_status_cb will besent.
- * @exception None
- * @version 3.0
- * @remark trackrenderer_audio_latency_stuats_cb \n
- * [in] userdata : userdata of
- * trackrenderer_audio_latency_status_cb
- * callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_audio_latency_stuats_cb
- */
-void trackrenderer_set_audio_latency_status_cb(
- TrackRendererHandle handle, trackrenderer_audio_latency_status_cb callback,
- void* userdata);
-
-/**
- * @brief Set video high latency callback function
- * @description If video high latency occurs, track renderer must send the
- * callback
- * to notify the application of the player buffer status.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] callback : trackrenderer_video_high_latency_cb ptr.
- * @param [in] userdata : userdata of
- * trackrenderer_high_latency_cb callback function.
- * @code
- * static void VideoHighLatencyCb(UserData userdata) {
- * //Something you want to do when high latency occurs *
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_video_high_latency_cb(handle,
- * VideoHighLatencyCb, nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
- * @post When video high latency occurs,
- * trackrenderer_video_high_latency_cb will be sent.
- * @exception None
- * @version 3.0
- * @remark trackrenderer_video_high_latency_cb \n
- * [in] userdata : userdata of
- * trackrenderer_video_high_latency_cb callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_video_high_latency_cb
- */
-void trackrenderer_set_video_high_latency_cb(
- TrackRendererHandle handle, trackrenderer_video_high_latency_cb callback,
- void* userdata);
-
-/**
- * @brief Set audio high latency callback function
- * @description If audio high latency occurs, track renderer must send the
- * callback
- * to notify the application of the player buffer status.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] callback : trackrenderer_audio_high_latency_cb ptr.
- * @param [in] userdata : userdata of
- * trackrenderer_audio_high_latency_cb callback function.
- * @code
- * refer to the sample code of
- * trackrenderer_set_video_high_latency_cb()
- * @endcode
- * @pre The trackrenderer must be at least created
- * @post When audio high latency occurs,
- * trackrenderer_audio_high_latency_cb will be
- * sent.
- * @exception None
- * @version 3.0
- * @remark trackrenderer_audio_high_latency_cb \n
- * [in] userdata : userdata of
- * trackrenderer_audio_high_latency_cb callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_set_audio_high_latency_cb
- */
-void trackrenderer_set_audio_high_latency_cb(
- TrackRendererHandle handle, trackrenderer_audio_high_latency_cb callback,
- void* userdata);
-
/**
* @brief Set seek done callback funciton.
* @description If seek operation is finished, the trackrenderer_seekdone_cb
* @param [in] callback : trackrenderer_seekdone_cb ptr.
* @param [in] userdata : userdata of trackrenderer_seekdone_cb callback
* function.
- * @code
- * refer to the sample code of trackrenderer_seek()
- * @endcode
- * @pre The trackrenderer must be at least created
+ * @pre None
* @post When seek done, app will handle the trackrenderer_seekdone_cb
* to decide next operation.
* @exception None
* @remark trackrenderer_seekdone_cb \n
* [in] userdata : userdata of trackrenderer_seekdone_cb callback
* function.
- * @see trackrenderer_create() \n
- * trackrenderer_seekdone_cb
*/
void trackrenderer_set_seekdone_cb(TrackRendererHandle handle,
trackrenderer_seekdone_cb callback,
* @param [in] callback : trackrenderer_flushdone_cb ptr.
* @param [in] userdata : userdata of trackrenderer_flushdone_cb callback
* function.
- * @code
- * refer to the sample code of trackrenderer_flush()
- * @endcode
- * @pre The trackrenderer must be at least created
+ * @pre None
* @post When flush done, app will handle the trackrenderer_flushdone_cb
* to decide next operation.
* @exception None
- * @version 2.0
+ * @version 2.0
* @remark trackrenderer_flushdone_cb \n
* [in] userdata : userdata of trackrenderer_flushdone_cb callback
* function.
- * @see trackrenderer_create() \n
- * trackrenderer_flushdone_cb
*/
void trackrenderer_set_flushdone_cb(TrackRendererHandle handle,
trackrenderer_flushdone_cb callback,
void* userdata);
+
/**
- * @brief Set event callback function
- * @description In this function set event callback to get event information.
- * If a specific event occurs, trackrenderer_event_cb will be
- * called to notify it with event information.
+ * @brief Set resolution change event callback function
+ * @description In this function set resolution change event callback to
+ * handle the event. If there is resolution change event,
+ * trackrenderer_event_cb will be called to notify resolution is
+ changed.
+ * The resolution info will be shared.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] callback : trackrenderer_event_cb ptr.
- * @param [in] userdata : userdata of trackrenderer_event_cb
- * callback function.
- * @code
- * static void OnEventCb(const TrackRendererEventType event_type,
- * const TrackrendererEventMsg msg_data,UserData userdata) {
- * //Something you want to do when the event occurs
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_event_cb(handle,OnEventCb, nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
- * @post App can get the information of the event that occured.
+ * @param [in] userdata : userdata of trackrenderer_event_cb callback
+ function.
+ * @pre None
+ * @post When resolution is changed, call trackrenderer_event_cb to
+ notice that
+ * resolution has been changed.
* @version 2.0
* @exception None
* @remark trackrenderer_event_cb
- * [in] event_type : event type that occured.
- * [in] msg_data : event message data.
- * [in] userdata : userdata of trackrenderer_event_cb callback
+ [in] event_type : Resolution change event type.
+ [in] msg_data : Resolution info.
+ [in] userdata : userdata of trackrenderer_event_cb callback
* function.
- * @see trackrenderer_create() \n
- * trackrenderer_event_cb
*/
void trackrenderer_set_event_cb(TrackRendererHandle handle,
trackrenderer_event_cb callback,
void* userdata);
/**
* @brief Set subtitle callback function
- * @description In this function set subtitle callback to handle the subtitle.
- * If there is subtitle to display trackrenderer_subtitle_rawdata_cb
- * will be called to notify there is subtitle to display.
- * The subtitle whole raw data will be shared. If user get this
- * callback and want to display the subtitle, user should get
- * subtitle informations from shared raw data.
+ * @description In this function set subtitle callback to handle the
+ * subtitle. If there is subtitle to display
+ * trackrenderer_subtitle_rawdata_cb will be called to notify there is subtitle
+ * to display. The subtitle whole raw data will be shared. If user get this
+ * callback and want to display the subtitle, user should get subtitle
+ * informations from shared raw data.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] callback : trackrenderer_subtitle_rawdata_cb ptr.
* @param [in] userdata : userdata of
* trackrenderer_subtitle_rawdata_cb callback function.
- * @code
- * static void SubtitleRawDataCb(TrackRendererDecoderInputBuffer* buf,
- * const TrackRendererSubtitleType type,
- * UserData userdata) {
- * //Something you want to do when there is subtitle data
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_subtitle_rawdata_cb(handle,SubtitleRawDataCb,nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
+ * @pre None
* @post When there is subtitledata, call
* trackrenderer_subtitle_rawdata_cb to notice that there is
* subtitle needed to be displayed.
* [in] type : subtitle type (text or picture) \n
* [in] userdata : userdata of
* trackrenderer_subtitle_rawdata_cb callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_subtitle_rawdata_cb
*/
void trackrenderer_set_subtitle_rawdata_cb(
TrackRendererHandle handle, trackrenderer_subtitle_rawdata_cb callback,
* @description (deprecated) In this function set subtitle callback to handle
* the subtitle. If there is subtitle to display
* trackrenderer_subtitledata_cb will be called to notify there
- * is subtitle to display. If user get this callback and want to display the
- * subtitle, user can use the shared subtitle informations.
+ * is subtitle to display. If user get this callback and want to display the
+ * subtitle, user can use the shared subtitle informations.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] callback : trackrenderer_subtitledata_cb ptr.
* @param [in] userdata : userdata of trackrenderer_subtitledata_cb
* callback function.
- * @code
- * static void SubtitleDataCb(const char* data, const int size,
- * const TrackRendererSubtitleType type,
- * const unsigned long long duration,
- * TrackRendererSubtitleAttr* attr_list,
- * int attr_list_size, UserData userdata) {
- * //Something you want to do when there is subtitle data
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_subtitledata_cb(handle,SubtitleDataCb,nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
+ * @pre None
* @post When there is subtitledata, call
- * trackrenderer_subtitledata_cb to notice that there is subtitle needed to be
- * displayed.
+ * trackrenderer_subtitledata_cb to notice that there is subtitle needed to be
+ * displayed.
* @exception None
* @remark trackrenderer_subtitledata_cb \n
* [in] data : subtitle data \n
* [in] attr_list_size : length of subtite attribute \n
* [in] userdata : userdata of trackrenderer_subtitledata_cb
* callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_subtitledata_cb
*/
void trackrenderer_set_subtitledata_cb(TrackRendererHandle handle,
trackrenderer_subtitledata_cb callback,
/**
* @brief Set EOS callback function
* @description In this function set EOS callback to handle EOS. If the
- * playing contents meet EOS, trackrenderer_eos_cb will be called
- * to notify the contents end.
+ * playing contents meet EOS, trackrenderer_eos_cb will be called to notify
+ * the contents end.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] callback : trackrenderer_eos_cb ptr.
* @param [in] userdata : userdata of trackrenderer_eos_cb callback
* function.
- * @code
- * static void EosCb(UserData userdata) {
- * //Something you want to do when contents meet EOS
- * printf("EOS received\n");
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_eos_cb(handle,EosCb,nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
- * @post When contents meet EOS, the trackrenderer_eos_cb will be
+ * @pre None
+ * @post When contents meet EOS, the trackrenderer_eos_cb will be
* called
* @exception None
* @remark trackrenderer_eos_cb \n
* [in] userdata : userdata of trackrenderer_eos_cb callback
* function.
- * @see trackrenderer_create() \n
- * trackrenderer_eos_cb
*/
void trackrenderer_set_eos_cb(TrackRendererHandle handle,
trackrenderer_eos_cb callback, void* userdata);
* @param [in] callback : trackrenderer_closedcaption_cb ptr.
* @param [in] userdata : userdata of trackrenderer_closedcaption_cb
* callback function.
- * @code
- * static void ClosedCaptionDataCb(const char* data,
- * const int size, UserData userdata) {
- * //Something you want to do when there is closed
- * caption needed to be displayed
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_closedcaption_cb(handle,ClosedCaptionDataCb,nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
+ * @pre None
* @post When there is closed caption data, call
* trackrenderer_closedcaption_cb to nofity that there is closed
* caption needed to be displayed.
* [in] size : length of closedcaption data \n
* [in] userdata : userdata of trackrenderer_closedcaption_cb
* callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_closedcaption_cb
*/
void trackrenderer_set_closedcaption_cb(TrackRendererHandle handle,
trackrenderer_closedcaption_cb callback,
* @brief Set drm initialize data callback function.
* @description In this function set drm initialize data callback. If
* trackrenderer detected any informations which need to
- * initiate drm, the trackrenderer_drminitdata_cb is called to
- * share the drm informations for dectyption.
+ * initiate drm, the trackrenderer_drminitdata_cb is called to share the drm
+ * informations for dectyption.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] callback : trackrenderer_drminitdata_cb ptr.
* @param [in] userdata : userdata of trackrenderer_drminitdata_cb
* callback function.
- * @code
- * static void DrmInitDataCb(int* drmhandle,unsigned int len,
- * unsigned char* psshdata, TrackRendererTrackType type,
- * UserData userdata) {
- * //Something you want to do when detect any drm data
- * printf("drm data received\n");
- * }
- * trackrenderer_create(&handle);
- * trackrenderer_set_drminitdata_cb(handle,DrmInitDataCb,nullptr);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created
+ * @pre None
* @post When the trackrenderer detect any drm data, call
* trackrenderer_drminitdata_cb function to share the init data.
- * @exception The trackrenderer must be at least created
+ * @exception None
* @remark trackrenderer_drminitdata_cb \n
* [in] drmhandle : drm handle \n
* [in] len : pssh data length \n
* [in] type : track type \n
* [in] userdata : userdata of trackrenderer_drminitdata_cb
* callback function.
- * @see trackrenderer_create() \n
- * trackrenderer_set_drminitdata_cb
*/
void trackrenderer_set_drminitdata_cb(TrackRendererHandle handle,
trackrenderer_drminitdata_cb callback,
* @brief Set current buffer status call back function
* @description In this function set buffer status callback function. If
* trackrenderer detected that there is not enough data or full
- * at trackrenderer buffer, call trackrenderer_bufferstatus_cb
- * to let user know what current buffer status is.
+ * at trackrenderer buffer, call trackrenderer_bufferstatus_cb to let user
+ * know what current buffer status is.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] callback : trackrenderer_bufferstatus_cb ptr.
* @param [in] userdata : userdata of trackrenderer_bufferstatus_cb
* callback function.
- * @code
- * refer to the sample code of trackrenderer_submit_packet()
- * @endcode
- * @pre The trackrenderer must be at least created
+ * @pre None
* @post When trackrenderer buffer status has changed to not enough or
* full, call trackrenderer_bufferstatus_cb()
* @exception None
* @remark trackrenderer_bufferstatus_cb \n
* [in] type : track type \n
* [in] status : trackrenderer buffer status \n
- * @see trackrenderer_create() \n
- * trackrenderer_bufferstatus_cb
*/
void trackrenderer_set_bufferstatus_cb(TrackRendererHandle handle,
trackrenderer_bufferstatus_cb callback,
* @brief Set seek data callback function
* @description In this function set seek data callback function. After
* flushing currently buffered data and trackrenderer is ready
- * to get new seeked position segment data, the
- * trackrenderer_seekdata_cb is called. If get this callback,
- * user can know the time to push new segment data.
+ * to get new seeked position segment data, the trackrenderer_seekdata_cb is
+ * called. If get this callback, user can know the time to push new segment
+ * data.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] callback : trackrenderer_seekdata_cb ptr.
* @param [in] userdata : userdata of trackrenderer_seekdata_cb
- * callback function.
- * @code
- * please refer to the sample code of trackrenderer_seek()
- * @endcode
- * @pre The trackrenderer must be at least created
+ * callback function.
+ * @pre None
* @post When trackrenderer finish to flush the buffered data for seek
* operation, call trackrenderer_seekdata_cb .
* @exception None
* @remark trackrenderer_seekdata_cb \n
* [in] type : track type \n
* [in] offset : the new seeked position \n
- * @see trackrenderer_create() \n
- * trackrenderer_seekdata_cb
*/
void trackrenderer_set_seekdata_cb(TrackRendererHandle handle,
trackrenderer_seekdata_cb callback,
void* userdata);
-/**
- * @brief Set tbm surface get callback function
- * @description In this function set bm surface get callback function.
- * After setting, user can get the useful tbm surface by
- * callback.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] callback :
- * trackrenderer_media_packet_video_tbmptr_cb ptr.
- * @param [in] userdata : userdata of callback function.
- * @pre None
- * @version 3.2
- * @post When trackrenderer would send decoded video buffer, call
- * trackrenderer_media_packet_video_tbmptr_cb .
- * @exception None
- * @remark trackrenderer_media_packet_video_tbmptr_cb \n
- * [in] ptr : pointer set to get the tbm surface data \n
- */
-void trackrenderer_set_media_packet_video_tbmptr_cb(
- TrackRendererHandle handle,
- trackrenderer_media_packet_video_tbmptr_cb callback, void* userdata);
-
/**
* @brief Set video decoded buffer callback function
* @description In this function set video decoded buffer callback function.
* callback.
* @param [in] handle : trackrenderer handle ptr.
* @param [in] media_packet_video_decoded_cb :
- * trackrenderer_media_packet_video_decoded_cb ptr.
+ * trackrenderer_media_packet_video_decoded_cb ptr.
* @param [in] userdata : userdata of media_packet_video_decoded_cb
* callback function.
- * @pre The trackrenderer must be at least created
- * @version 2.0
+ * @pre None
+ * @version 2.0
* @post When trackrenderer decoded video buffer, call
- * trackrenderer_media_packet_video_decoded_cb .
+ * trackrenderer_media_packet_video_decoded_cb .
* @exception None
* @remark trackrenderer_media_packet_video_decoded_cb \n
* [in] packet : packet including decoded buffer \n
- * @see trackrenderer_create() \n
- * trackrenderer_media_packet_video_decoded_cb
*/
void trackrenderer_set_media_packet_video_decoded_cb(
TrackRendererHandle handle,
trackrenderer_media_packet_video_decoded_cb media_packet_video_decoded_cb,
void* userdata);
-/**
- * @brief Set multiview start video callback function
- * @description Entering mulview mode, if ResourceCenter sends
- * video start request to a player when it's required, the callback function
- * will be invoked. User must activate new stream by trackrenderer_activate()
- * before callback returns, and seek to current playing position.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] callback : trackrenderer_multiview_start_video_cb ptr.
- * @param [in] userdata : userdata of
- * trackrenderer_multiview_start_video_cb callback function.
- * @pre The trackrenderer must be created but before
- * trackrenderer_prepare()
- * @post When ResourceCenter sends video start request to a player,
- * trackrenderer_multiview_start_video_cb will be sent.
- * @exception None
- * @version 3.1
- * @remark trackrenderer_multiview_start_video_cb \n
- * [in] userdata : userdata of
- * trackrenderer_multiview_start_video_cb callback function.
- * @see trackrenderer_activate() \n
- * trackrenderer_seek() \n
- * trackrenderer_seek2() \n
- */
-void trackrenderer_set_multiview_start_video_cb(
- TrackRendererHandle handle, trackrenderer_multiview_start_video_cb callback,
- void* userdata);
-
-/**
- * @brief Set multiview stop video callback function
- * @description Entering mulview mode, if ResourceCenter sends
- * video stop request to a player when it's required, the callback function will
- * be invoked. User must stop video packet feeding, and deactivate video stream
- * by trackrenderer_deactivate() before callback returns.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] callback : trackrenderer_multiview_stop_video_cb ptr.
- * @param [in] userdata : userdata of
- * trackrenderer_multiview_stop_video_cb callback function.
- * @pre The trackrenderer must be created but before
- * trackrenderer_prepare()
- * @post When ResourceCenter sends video start request to a player,
- * trackrenderer_multiview_stop_video_cb will be sent.
- * @exception None
- * @version 3.1
- * @remark trackrenderer_multiview_stop_video_cb \n
- * [in] userdata : userdata of
- * trackrenderer_multiview_stop_video_cb callback function.
- * @see trackrenderer_deactivate() \n
- */
-void trackrenderer_set_multiview_stop_video_cb(
- TrackRendererHandle handle, trackrenderer_multiview_stop_video_cb callback,
- void* userdata);
-
-/**
- * @brief Initialize easing info to trackrenderer.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] init_volume : initial easing volume (0 ~ 100).
- * @param [in] init_elapsed_time : initial elapsed time (millisecond).
- * @param [in] easing_info : target volume, duration, type.
- * @return 0 on success, otherwise -1 failed.
- * @code
- * trackrenderer_create(&handle);
- * const TrackRendererAudioEasingInfo init_info =
- * {0,1000,kTrackRendererAudioEasingLinear};
- * trackrenderer_init_audio_easing_info(handle, 100, 0,
- * &init_info);
- * //your logic
- * const TrackRendererAudioEasingInfo update_info =
- * {100,1000,kTrackRendererAudioEasingLinear};
- * trackrenderer_update_audio_easing_info(handle, &update_info));
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created.
- * @post None
- * @exception None
- * @remark None
- * @version 3.0
- * @see trackrenderer_create()
- */
-int trackrenderer_init_audio_easing_info(
- TrackRendererHandle handle, const uint32_t init_volume,
- const uint32_t init_elapsed_time,
- const TrackRendererAudioEasingInfo* easing_info);
-
-/**
- * @brief Update easing info to trackrenderer.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] easing_info : target volume, duration, type.
- * @return 0 on success, otherwise -1 failed.
- * @code
- * refer to the sample code of
- * trackrenderer_init_audio_easing_info()
- * @endcode
- * @pre The trackrenderer must be at least created.
- * This api should be called after
- * trackrenderer_init_audio_easing_info() is called
- * @post None
- * @exception None
- * @remark None
- * @version 3.0
- * @see trackrenderer_create() \n
- * trackrenderer_init_audio_easing_info()
- */
-int trackrenderer_update_audio_easing_info(
- TrackRendererHandle handle,
- const TrackRendererAudioEasingInfo* easing_info);
-
-/**
- * @brief Get easing info currently in easing operation from
- * trackrenderer
- * @param [in] handle : trackrenderer handle ptr.
- * @param [out] current_volume : current volume (0 ~ 100).
- * @param [out] elapsed_time : elapsed time (millisecond).
- * @param [out] easing_info : target volume, duration, type.
- * @return 0 on success, otherwise -1 failed.
- * @code
- * trackrenderer_create(&handle);
- * const TrackRendererAudioEasingInfo init_info =
- * {0,1000,kTrackRendererAudioEasingLinear};
- * trackrenderer_init_audio_easing_info(handle, 100, 0,
- * &init_info);
- * //your logic
- * uint32_t cur_volume = 0;
- * uint32_t elapsed_time = 0;
- * TrackRendererAudioEasingInfo get_info;
- * trackrenderer_get_audio_easing_info(handle, &cur_volume,
- * &elapsed_time, &get_info);
- * //your logic
- * trackrenderer_destroy(handle);
- * @endcode
- * @pre The trackrenderer must be at least created.
- * This api should be called after
- * trackrenderer_init_audio_easing_info() is called
- * @post None
- * @exception None
- * @remark None
- * @version 3.0
- * @see trackrenderer_create() \n
- * trackrenderer_init_audio_easing_info()
- */
-int trackrenderer_get_audio_easing_info(
- TrackRendererHandle handle, uint32_t* current_volume,
- uint32_t* elapsed_time, TrackRendererAudioEasingInfo* easing_info);
-
-/**
- * @brief Start audio easing using a registered audio easing info
- * @param [in] handle : trackrenderer handle ptr.
- * @return 0 on success, otherwise -1 failed.
- * @code
- * trackrenderer_create(&handle);
- * const TrackRendererAudioEasingInfo init_info =
- * {0,1000,kTrackRendererAudioEasingLinear};
- * trackrenderer_init_audio_easing_info(handle, 100, 0,
- * &init_info);
- * trackrenderer_prepare(handle);
- * trackrenderer_start_audio_easing(handle);
- * //your logic
- * trackrenderer_stop_audio_easing(handle);
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
- * @pre The trackrenderer must be at least created and set up.
- * This api should be called after
- * trackrenderer_init_audio_easing_info() is called
- * @post None
- * @exception None
- * @remark None
- * @version 3.0
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_init_audio_easing_info()
- */
-int trackrenderer_start_audio_easing(TrackRendererHandle handle);
-
-/**
- * @brief Stop audio easing
- * @param [in] handle : trackrenderer handle ptr.
- * @return 0 on success, otherwise -1 failed.
- * @code
- * refer to the sample code of trackrenderer_start_audio_easing()
- * @endcode
- * @pre The trackrenderer must be at least created.
- * This api should be called after
- * trackrenderer_init_audio_easing_info() is called
- * @post None
- * @exception None
- * @remark None
- * @version 3.0
- * @see trackrenderer_create() \n
- * trackrenderer_prepare() \n
- * trackrenderer_start_audio_easing() \n
- * trackrenderer_init_audio_easing_info()
- */
-int trackrenderer_stop_audio_easing(TrackRendererHandle handle);
-
-/**
- * @brief Get virtual resource id
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] type : the resource type of virtual id.
- * @param [out] virtual_id : Stored virtual resource id value.
- * @return 0 on success, otherwise -1 failed.
- * @code
- * //prepare trackrenderer hanle *
- * //your logic
- * int virtual_id = -1;
- * trackrenderer_get_virtual_rsc_id(
- * handle, kTrackRendererRscTypeVideoRenderer, &virtual_id);
- * //your logic
- * trackrenderer_stop(handle);
- * @endcode
- * @pre The trackrenderer must be at least created and set up.
- * @post None
- * @exception None
- * @remark None
- * @version 3.0
- * @see trackrenderer_create() \n
- * trackrenderer_prepare()
- */
-int trackrenderer_get_virtual_rsc_id(TrackRendererHandle handle,
- TrackRendererRscType type,
- int* virtual_id);
-
-/**
- * @brief Set advanced picture quality type
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] type : the advanced picture quality type.
- * @return 0 on success, otherwise -1 failed.
- * @pre The trackrenderer must be at least created.
- * trackrenderer_create()
- * @post None
- * @exception None
- * @remark None
- * @version 3.1
- */
-int trackrenderer_set_advanced_picture_quality_type(
- TrackRendererHandle handle, TrackRendererAdvPictureQualityType type);
-
-/**
- * @brief Set resource allocate policy
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] policy : the resource allocate policy.
- * @return 0 on success, otherwise -1 failed.
- * @pre The trackrenderer must be at least created.
- * trackrenderer_create()
- * @post None
- * @exception None
- * @remark None
- * @version 3.2
- */
-int trackrenderer_set_resource_allocate_policy(
- TrackRendererHandle handle, TrackRendererRscAllocPolicy policy);
-
-/**
- * @brief Set video's par(pixel aspect ratio) and dar(display aspect
- * ratio)
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] time_millisecond : timestamp when par and dar will
- * changed.
- * @param [in] par_num : par_num : numerator of par.
- * @param [in] par_den : par_den : denominator of par.
- * @param [in] dar_num : dar_num : numerator of dar.
- * @param [in] dar_den : dar_den : denominator of dar.
- * @return 0 on success, otherwise -1 failed.
- * @pre The trackrenderer must be at least created.
- * trackrenderer_create()
- * @post None
- * @exception None
- * @remark None
- * @version 3.3
- */
-int trackrenderer_set_video_par_dar(TrackRendererHandle handle,
- uint64_t time_millisecond, uint32_t par_num,
- uint32_t par_den, uint32_t dar_num,
- uint32_t dar_den);
-
#ifdef __cplusplus
} // extern "C"
#endif
+
/**
* @file trackrenderer_internal.h
* @brief trackrenderer internally used api c version
#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACKRENDERER_INTERNAL_H__
#include "trackrenderer_capi/display.h"
-#include "trackrenderer_capi/track_capi.h"
#ifdef __cplusplus
extern "C" {
#endif
-/**
- * @brief video decoded buffer struct (raw mode)
- */
-typedef struct {
- /**
- * @description buffer pts, in millisecond
- */
- uint64_t pts;
- /**
- * @description width
- */
- uint32_t width;
- /**
- * @description height
- */
- uint32_t height;
- /**
- * @description internal data
- */
- void* internal_data;
-} TrackRendererDecodedVideoRawModePacket;
-
-/**
- * @brief Enumerations for types of video decoded buffer (raw mode)
- */
-enum TrackRendererDecodedVideoType {
- kTrackRendererDecodedVideoPhysicalAddressType,
- kTrackRendererDecodedVideoTizenBufferType,
-};
-
-/**
- * @brief Enumerations for video decoded buffer type
- */
-enum TrackRendererDecodedVideoFrameBufferTypeExt {
- kTrackRendererDecodedVideoFrameBufferExtNone,
- kTrackRendererDecodedVideoFrameBufferExtRaw
-};
-
-/**
- * @brief Enumerations for video renderer type
- */
-enum TrackRendererVideoRendererType {
- TrackRendererVideoRendererTypeMain,
- TrackRendererVideoRendererTypeSub,
- TrackRendererVideoRendererTypeSub2,
- TrackRendererVideoRendererTypeSub3,
-};
-
typedef void* TrackRendererHandle;
-typedef void (*trackrenderer_first_decoding_done_cb)(void* userdata);
-
-/**
- * @description When trackrenderer detected that there is not enough data at
- * decoder output buffer, call this function to let user know
- * current buffer status.
- * @param [in] userdata : userdata of
- * trackrenderer_decoder_underrun_cb callback function.
- * @pre The callback function should be set by
- * trackrenderer_set_decoder_underrun_cb, in advance.
- * @post User can control data feeding speed with this change callback.
- * @see trackrenderer_set_decoder_underrun_cb()
- */
-typedef void (*trackrenderer_decoder_underrun_cb)(void* userdata);
-
-/**
- * @description When trackrenderer finish to decode video buffer,
- * this is called, then user can get the decoded video buffer
- * @param [in] packet : decoded video packet \n
- * [in] type : the type of decoded video packet.
- * (tbm_key or h/w decoded) \n
- * @pre The callback function should be set by
- * trackrenderer_set_media_packet_video_raw_decoded_cb,
- * in advance.
- * @post User can use the decoded buffer to render.
- * @see trackrenderer_set_media_packet_video_raw_decoded_cb()
- */
-typedef void (*trackrenderer_media_packet_video_raw_decoded_cb)(
- const TrackRendererDecodedVideoRawModePacket* packet,
- TrackRendererDecodedVideoType type, void* userdata);
/**
* @brief Set the video display properties.
TrackRendererDisplayType type,
void* ecore_wl2_window, int x,
int y, int w, int h);
-/**
- * @brief Set first decoding done call back function
- * @description in this function set first decoding done callback function.
- * It wil be invoked when the first video frame is decoded.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] callback : trackrenderer_first_decoding_done_cb ptr.
- * @param [in] userdata : userdata of
- * trackrenderer_first_decoding_done_cb callback function.
- * @pre "video-frame-peek-mode" attribute of
- * trackrenderer_set_attribute() have to be set.
- * @post When the first video frame is decoded, call
- * trackrenderer_first_decoding_done_cb()
- * @exception None
- * @remark trackrenderer_first_decoding_done_cb \n
- */
-void trackrenderer_set_first_decoding_done_cb(
- TrackRendererHandle handle, trackrenderer_first_decoding_done_cb callback,
- void* userdata);
-
-/**
- * @brief Set video decoder underrun status call back function
- * @description In this function set buffer status callback function. If
- * trackrenderer detected that not enough data at decoder output
- * buffer, call trackrenderer_decoder_underrun_cb to let user
- * know current buffer status.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] callback : trackrenderer_decoder_underrun_cb ptr.
- * @param [in] userdata : userdata of trackrenderer_decoder_underrun_cb
- * callback function.
- * @pre None
- * @post When video decoder buffer status has changed to not enough,
- * call trackrenderer_decoder_underrun_cb()
- * @exception None
- * @remark trackrenderer_decoder_underrun_cb \n
- */
-void trackrenderer_set_video_decoder_underrun_cb(
- TrackRendererHandle handle, trackrenderer_decoder_underrun_cb callback,
- void* userdata);
-
-/**
- * @brief Set active track info to set up trackrenderer properties.
- * @description In this fuction, trackrenderer set track info which is
- * necessary for media contents playback.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] handles_array : Active track handles for playing media
- * contents.
- * @param [in] array_size : Number of tracks. The maximum number of
- * tracks is 3.(audio, video, subtitle)
- * @return Return 0 if there are any active tracks among audio, video,
- * subtitle and successcully set the track info to trackrenderer.
- * Otherwise -1 if there is not any active tracks or already set
- * tracks info.
- * @pre This api should never be called before.
- * @post TrackRenderer sets factories to create pipeline using tracks
- * passed.
- * @exception None
- * @remark None
- * @see trackrenderer_track_create()\n
- * trackrenderer_track_destroy()
- */
-int trackrenderer_set_track_handle(
- TrackRendererHandle handle, const TrackRendererTrackHandle* handles_array,
- const int array_size);
-
-/**
- * @brief Provided api for setting alternative audio resource(sub decoder
- * and sub out)
- * @description In this fuction, trackrenderer select the main or sub among the
- * HW resources.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] rsc_type : set alternative audio resource
- * (@c 0 = default audio resource(main), @c 1 = audio sub
- * resource)
- * @return Return 0 if set the audio resource type.
- * Otherwise -1 if the trackrenderer is not even setup.
- * @pre The trackrenderer must be at least created.
- * trackrenderer_create()
- * @post None
- * @exception None
- * @remark None
- */
-
-int trackrenderer_set_alternative_audio_resource(TrackRendererHandle handle,
- unsigned int rsc_type);
-
-/**
- * @brief Set decoded video frame buffer extended type.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] type : one of the video decoded buffer type to set .
- * @pre The trackrenderer must be at least created but before prepare.
- * trackrenderer_create()
- * @post None
- * @exception None
- */
-void trackrenderer_set_video_frame_buffer_type_ext(
- TrackRendererHandle handle,
- TrackRendererDecodedVideoFrameBufferTypeExt type);
-
-/**
- * @brief Set video decoded raw buffer callback function
- * @description In this function set video decoded buffer callback function.
- * After setting, user can get the video decoded buffers by
- * callback.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] media_packet_video_decoded_cb :
- * trackrenderer_media_packet_video_raw_decoded_cb ptr.
- * @param [in] userdata : userdata of media_packet_video_decoded_cb
- * callback function.
- * @pre None
- * @post When trackrenderer decoded video buffer, call
- * trackrenderer_media_packet_video_raw_decoded_cb.
- * @exception None
- * @remark trackrenderer_media_packet_video_decoded_cb \n
- * [in] packet : packet including decoded buffer \n
- * [in] type : the type of decoded video packet.
- * (tbm_key or h/w decoded) \n
- */
-void trackrenderer_set_media_packet_video_raw_decoded_cb(
- TrackRendererHandle handle,
- trackrenderer_media_packet_video_raw_decoded_cb
- media_packet_video_decoded_cb,
- void* userdata);
-
-/**
- * @brief Set video renderer type. It overrides the scaler type from
- * trackrenderer_set_attribute(handle,
- * "alternative-video-resource", type, nullptr)
- * It also depends on target which support multi video renderer.
- * @param [in] handle : trackrenderer handle ptr.
- * @param [in] type : video renderer type
- * @return Return 0 if set the video renderer type.
- * Otherwise -1 if the video renderer type is not even setup.
- * @pre None
- * @post None
- * @see TrackRendererVideoRendererType
- */
-int trackrenderer_set_video_renderer_type(
- TrackRendererHandle handle, TrackRendererVideoRendererType renderer_type);
-
#ifdef __cplusplus
}
#endif
--- /dev/null
+\r
+prefix = @PREFIX@\r
+exec_prefix = /usr\r
+libdir = @LIB_INSTALL_DIR@\r
+\r
+Name: @PC_NAME@\r
+Description: @PACKAGE_DESCRIPTION@\r
+Version: @VERSION@\r
+Libs: -L${libdir} @PC_LDFLAGS@\r
+Cflags : @PC_CFLAGS@\r
+++ /dev/null
-<manifest>\r
- <request>\r
- <domain name="_" />\r
- </request>\r
-</manifest>
\ No newline at end of file
+++ /dev/null
-# %bcond_with : disable TRACKRENDERER_CAPI_UT by default, %bcond_without : enable TRACKRENDERER_CAPI_UT
-%bcond_without TRACKRENDERER_CAPI_UT
-Name: capi-trackrenderer-tv
-Summary: new multimedia streaming player capi-trackrenderer-tv
-Version: 0.0.1
-Release: 0
-Group: Multimedia/Libraries
-License: Apache-2.0
-Source0: %{name}-%{version}.tar.gz
-Source1001: capi-trackrenderer-tv.manifest
-BuildRequires: cmake
-BuildRequires: pkgconfig(glib-2.0)
-BuildRequires: pkgconfig(capi-base-common)
-BuildRequires: pkgconfig(gstreamer-1.0)
-BuildRequires: pkgconfig(gstreamer-plugins-base-1.0)
-BuildRequires: pkgconfig(dlog)
-BuildRequires: pkgconfig(boost)
-BuildRequires: pkgconfig(elementary)
-BuildRequires: pkgconfig(ecore)
-BuildRequires: pkgconfig(evas)
-BuildRequires: pkgconfig(ecore-wl2)
-BuildRequires: pkgconfig(wayland-client)
-BuildRequires: pkgconfig(tizen-extension-client)
-BuildRequires: pkgconfig(tv-resource-manager)
-BuildRequires: pkgconfig(tv-resource-information)
-BuildRequires: pkgconfig(resource-center-api)
-BuildRequires: pkgconfig(audio-control)
-BuildRequires: pkgconfig(libtzplatform-config)
-BuildRequires: pkgconfig(jsoncpp)
-BuildRequires: pkgconfig(gstreamer-ffsubtitle-1.0)
-BuildRequires: pkgconfig(icu-i18n)
-BuildRequires: pkgconfig(drmdecrypt)
-BuildRequires: pkgconfig(vconf)
-BuildRequires: pkgconfig(capi-system-info)
-BuildRequires: pkgconfig(logger)
-BuildRequires: pkgconfig(gio-2.0)
-BuildRequires: pkgconfig(factory-api)
-BuildRequires: pkgconfig(libtbm)
-BuildRequires: pkgconfig(lwipc)
-BuildRequires: pkgconfig(capi-screensaver)
-BuildRequires: pkgconfig(context-aware-api)
-BuildRequires: pkgconfig(vd-win-util)
-BuildRequires: pkgconfig(iniparser)
-
-%if ("%{_vd_cfg_product_type}" == "AUDIO")
-BuildRequires: pkgconfig(libavoc-av)
-%else
-BuildRequires: pkgconfig(libavoc)
-BuildRequires: pkgconfig(graphics-control)
-%endif
-
-%if ("%{_vd_cfg_licensing}" == "n")
-# for ut
-BuildRequires: pkgconfig(capi-media-player)
-BuildRequires: pkgconfig(gtest_gmock)
-BuildRequires: pkgconfig(appcore-efl)
-BuildRequires: pkgconfig(libresourced)
-%endif
-
-%define _packagedir /usr
-%define _bindir %{_packagedir}/bin
-%define _libdir %{_packagedir}/lib
-%define _includedir %{_packagedir}/include
-%define _pkgconfigdir %{_libdir}/pkgconfig
-%define _unpackaged_files_terminate_build 0
-%define _missing_doc_files_terminate_build 0
-
-%description
-new multimedia player, object-oriented model
-
-%package devel
-Summary: Developement for multimedia player
-Group: Development/Libraries
-Requires: %{name} = %{version}-%{release}
-
-%package config
-Summary: Configuration for multimedia player
-Group: Development/Libraries
-Requires: %{name} = %{version}-%{release}
-
-%description devel
-%devel_desc
-
-%description config
-
-#################################################
-# gcov
-#################################################
-%if 0%{?vd_gcov:1}
-%package gcov
-Summary: gcov enabled package
-Group: gcov package
-
-%description gcov
-This package is gcov package for coverage measurement.
-%endif
-
-%prep
-%setup -q
-cp %{SOURCE1001} .
-
-%if ("%{_vd_cfg_licensing}" == "n")
-
-%{?!TOMATO: %define TOMATO n}
-
-%define _tomatoname trackrenderer_capi
-%define _tomatodir /opt/usr/apps/tomato/testcase/%{name}
-%define _tomatobin /opt/usr/apps/tomato/testcase/%{name}/bin
-
-%package ut-component-tomato
-Summary: Test package with TOMATO
-BuildRequires: pkgconfig(tomato)
-BuildRequires: pkgconfig(gtest_gmock)
-Requires: %{name} = %{version}-%{release}
-
-%description ut-component-tomato
-This package is for test
-
-%files ut-component-tomato
-%defattr(-,root,root,-)
-%{_bindir}/capi-trackrenderer-tv_ut
-%{_tomatodir}/*
-
-%endif
-
-%build
-export CFLAGS+=" -Wno-deprecated-declarations"
-export CXXFLAGS+=" -Wno-deprecated-declarations"
-
-%if ("%{_vd_cfg_product_type}" == "AV")
-export CFLAGS+=" -DIS_AV_PRODUCT"
-export CXXFLAGS+=" -DIS_AV_PRODUCT"
-%endif
-
-export CFLAGS+=" -DPLUS_PLAYER_AI_DATA_COLLECTION"
-export CXXFLAGS+=" -DPLUS_PLAYER_AI_DATA_COLLECTION"
-
-%if ("%{_vd_cfg_product_type}" == "AUDIO")
-export CFLAGS+=" -DSOUNDBAR_PRODUCT"
-export CXXFLAGS+=" -DSOUNDBAR_PRODUCT"
-%define _support_soundbar -DSUPPORT_SOUNDBAR=ON
-%endif
-
-%if ("%{_vd_cfg_licensing}" == "n")
-%if %{with TRACKRENDERER_CAPI_UT}
-%define _trackrenderer_capi_ut -DTRACKRENDERER_BUILD_UT=ON
-%endif
-%endif
-
-%if 0%{?vd_gcov:1}
-export CFLAGS+=" -fprofile-arcs -ftest-coverage"
-export CXXFLAGS+=" -fprofile-arcs -ftest-coverage"
-export FFLAGS+=" -fprofile-arcs -ftest-coverage"
-export LDFLAGS+=" -lgcov"
-%endif
-
-%cmake \
- %{?_trackrenderer_capi_ut:%_trackrenderer_capi_ut} \
- %{?_support_soundbar:%_support_soundbar}
-
-make %{?jobs:-j%jobs}
-
-%install
-rm -rf %{buildroot}
-
-%if ("%{_vd_cfg_licensing}" == "n")
-mkdir -p %{buildroot}%{_tomatodir}
-mkdir -p %{buildroot}%{_tomatodir}/log
-mkdir -p %{buildroot}%{_tomatodir}/result
-mkdir -p %{buildroot}%{_tomatodir}/tc
-cp -rf tomato/tc/* %{buildroot}%{_tomatodir}/tc
-%endif
-
-%make_install
-
-%if 0%{?vd_gcov:1}
-mkdir -p %{buildroot}%{_datadir}/gcov/obj
-find . \( -name '*.gcno' -o -name '*.cpp' -o -name '*.c' -o -name '*.hpp' -o -name '*.h' \) ! -path "./ut/*" ! -path "./test/*" ! -path "*/CompilerIdCXX/*" -exec cp --parents -r '{}' %{buildroot}%{_datadir}/gcov/obj ';'
-%endif
-
-%files
-%defattr(-,root,root,-)
-%manifest capi-trackrenderer-tv.manifest
-%license LICENSE.APLv2
-%{_libdir}/libtrackrenderer.so
-
-%if ("%{_vd_cfg_licensing}" == "n")
-%if %{with TRACKRENDERER_CAPI_UT}
-%{_bindir}/capi-trackrenderer-tv_ut
-%defattr(-,root,root,-)
-%{_tomatodir}/*
-%endif
-%endif
-
-%files devel
-%defattr(-,root,root,-)
-%{_includedir}/trackrenderer_capi/*.h
-%{_pkgconfigdir}/capi-trackrenderer-tv.pc
-
-%files config
-%defattr(-,root,root,-)
-%manifest capi-trackrenderer-tv.manifest
-%license LICENSE.APLv2
-
-%if 0%{?vd_gcov:1}
-%files gcov
-%{_datadir}/gcov/*
-%endif
--- /dev/null
+<manifest>\r
+ <request>\r
+ <domain name="_" />\r
+ </request>\r
+</manifest>
\ No newline at end of file
--- /dev/null
+Name: libtrackrenderer
+Summary: new multimedia streaming player trackrenderer
+Version: 0.0.1
+Release: 0
+Group: Multimedia/Libraries
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+Source1001: libtrackrenderer.manifest
+BuildRequires: cmake
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(capi-base-common)
+BuildRequires: pkgconfig(gstreamer-1.0)
+BuildRequires: pkgconfig(gstreamer-base-1.0)
+BuildRequires: pkgconfig(gstreamer-video-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(jsoncpp)
+BuildRequires: pkgconfig(icu-i18n)
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(capi-system-info)
+BuildRequires: pkgconfig(gio-2.0)
+BuildRequires: pkgconfig(libtbm)
+BuildRequires: pkgconfig(mm-resource-manager)
+BuildRequires: gtest-devel
+BuildRequires: gtest
+
+%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
+
+%prep
+%setup -q
+cp %{SOURCE1001} .
+
+%build
+%cmake .
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+
+%make_install
+
+%files
+%defattr(-,root,root,-)
+%manifest libtrackrenderer.manifest
+%license LICENSE.APLv2
+%{_libdir}/libtrackrenderer.so
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/trackrenderer_capi/*.h
+%{_pkgconfigdir}/libtrackrenderer.pc
+
+%files config
+%defattr(-,root,root,-)
+%manifest libtrackrenderer.manifest
+%license LICENSE.APLv2
+
SET(${fw_name}_CXXFLAGS "-Wall -Werror -std=c++11 -fPIC -Wl,-z,relro -fstack-protector -DEFL_BETA_API_SUPPORT")
-SET(dependents "gstreamer-1.0 gstreamer-ffsubtitle-1.0"
+SET(dependents "gstreamer-1.0 gstreamer-video-1.0"
"boost"
"vconf"
- "tv-resource-manager"
"elementary ecore ecore-wl2"
- "audio-control"
"libtbm"
- "capi-screensaver"
- "lwipc"
- "vd-win-util"
"jsoncpp"
"capi-system-info"
- "iniparser"
- "drmdecrypt"
- "resource-center-api")
-
-IF(SUPPORT_SOUNDBAR)
-SET(dependents ${dependents} "libavoc-av")
-ELSE(SUPPORT_SOUNDBAR)
-SET(dependents ${dependents} "libavoc" "graphics-control")
-ENDIF(SUPPORT_SOUNDBAR)
+ "mm-resource-manager")
INCLUDE(FindPkgConfig)
${PROJECT_SOURCE_DIR}/caps_recipes.cpp
${PROJECT_SOURCE_DIR}/display.cpp
${PROJECT_SOURCE_DIR}/error.cpp
- ${PROJECT_SOURCE_DIR}/latency_manager.cpp
${PROJECT_SOURCE_DIR}/trackrenderer.cpp
${PROJECT_SOURCE_DIR}/trackrenderer_attr.cpp
${PROJECT_SOURCE_DIR}/trackrenderer_capi.cpp
${PROJECT_SOURCE_DIR}/gstobject_guard.cpp
${PROJECT_SOURCE_DIR}/gstsignal_holder.cpp
${PROJECT_SOURCE_DIR}/track_util.cpp
- ${PROJECT_SOURCE_DIR}/screen_saver.cpp
- ${PROJECT_SOURCE_DIR}/track_capi.cpp
- ${PROJECT_SOURCE_DIR}/trackrenderer_vconf.cpp
- # temporary, this will be remove when trackrenderer/subtitle_attr_parser deprecation.
- ${PROJECT_SOURCE_DIR}/subtitle_attr_parser.cpp
- ${PROJECT_SOURCE_DIR}/audio_easing_controller.cpp
- ${PROJECT_SOURCE_DIR}/vr360.cpp
)
ADD_LIBRARY(${fw_name} SHARED ${CC_SRCS})
+++ /dev/null
-//
-// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#include "trackrenderer/audio_controller/audio_easing_controller.h"
-
-#include <algorithm>
-#include <chrono>
-#include <unordered_map>
-
-#include "trackrenderer/core/gstobject_guard.h"
-#include "trackrenderer/core/utils/log.h"
-
-namespace plusplayer {
-
-namespace trackrenderer {
-namespace internal {
-
-bool IsValidVolume(const uint32_t volume) {
- constexpr uint32_t kVolumeMax = 100;
- if (volume > kVolumeMax) {
- TRACKRENDERER_ERROR("volume: %d", volume);
- return false;
- }
- return true;
-}
-
-void UpdateInfo(AudioEasingInfo* dest, const AudioEasingInfo* src) {
- TRACKRENDERER_ERROR(
- "target vol [%u - %u] / duration [%u - %u] / type [%d - %d]",
- dest->target_volume, src->target_volume, dest->duration, src->duration,
- static_cast<int>(dest->type), static_cast<int>(src->type));
-
- *dest = *src;
-}
-
-uint32_t GetMicroSecStepInterval(uint32_t duration_us) {
- constexpr uint32_t kDefaultEaseSteps = 400;
- constexpr uint32_t kDefaultInterval = 10000;
-
- uint32_t interval = duration_us / kDefaultEaseSteps;
- return std::max(interval, kDefaultInterval);
-}
-
-using SystemClockType = std::chrono::system_clock::time_point;
-uint32_t GetMicroSecElapsedEasingTime(SystemClockType begin) {
- auto end = std::chrono::system_clock::now();
- auto real_elapsed_time =
- std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
-
- return real_elapsed_time.count();
-}
-
-void WaitGap(uint32_t end, uint32_t begin) {
- if (begin > end) return;
-
- auto wait = end - begin;
- if (wait > 0) {
- std::this_thread::sleep_for(std::chrono::microseconds(wait));
- }
-}
-
-constexpr int kTimeFactor = 1000;
-uint32_t ConvertMsToMicroSec(uint32_t ms) {
- uint32_t us = ms * kTimeFactor;
- return us;
-}
-uint32_t ConvertMicroSecToMs(uint32_t us) {
- uint32_t ms = us / kTimeFactor;
- return ms;
-}
-
-} // namespace internal
-
-constexpr int kMaxVolumeIndex = 101;
-const int kVolumeToGainIndexTable[kMaxVolumeIndex] = {
- 0, 7, 12, 17, 20, 24, 28, 32, 34, 37, // 9
- 39, 42, 43, 46, 47, 48, 49, 51, 52, 53, // 19
- 54, 56, 57, 57, 58, 59, 61, 61, 62, 62, // 29
- 63, 64, 64, 66, 66, 67, 67, 68, 68, 69, // 39
- 69, 71, 71, 71, 72, 72, 73, 73, 73, 74, // 49
- 74, 74, 76, 76, 76, 77, 77, 77, 78, 78, // 59
- 78, 78, 79, 79, 79, 81, 81, 81, 81, 82, // 69
- 82, 82, 82, 83, 83, 83, 83, 83, 84, 84, // 79
- 84, 84, 86, 86, 86, 86, 86, 87, 87, 87, // 89
- 87, 87, 88, 88, 88, 88, 88, 88, 89, 89, // 99
- 89};
-
-AudioEasingController::AudioEasingController(uint32_t init_volume,
- uint32_t init_elapsed_time,
- const AudioEasingInfo& init_info) {
- TRACKRENDERER_ENTER;
- is_stopped_.store(true);
- AudioEasingController::SetInfo(init_info);
- volume_.store(init_volume);
- initial_volume_.store(init_volume);
- elapsed_time_ms_.store(init_elapsed_time); // have the dependency of sequence
- TRACKRENDERER_LEAVE;
-}
-
-AudioEasingController::~AudioEasingController() {
- TRACKRENDERER_ENTER;
- if (easing_task_.joinable()) {
- TRACKRENDERER_ERROR("join before");
- easing_task_.join();
- TRACKRENDERER_ERROR("join after");
- }
-}
-
-int AudioEasingController::GetGainFromVolume(uint32_t volume) {
- TRACKRENDERER_ENTER;
- if (volume > kMaxVolumeIndex) return -1;
- return kVolumeToGainIndexTable[volume];
-}
-
-bool AudioEasingController::GetInfo(uint32_t* current_volume,
- uint32_t* elapsed_time,
- AudioEasingInfo* info) {
- TRACKRENDERER_ENTER;
- if (current_volume == nullptr || elapsed_time == nullptr || info == nullptr) {
- TRACKRENDERER_ERROR("input param is nullptr");
- return false;
- }
-
- *current_volume = volume_.load();
- *elapsed_time = elapsed_time_ms_.load();
- TRACKRENDERER_ERROR("%u - %u / %u - %u", *current_volume, volume_.load(),
- *elapsed_time, elapsed_time_ms_.load());
-
- std::lock_guard<std::mutex> info_lock(current_info_m_);
- internal::UpdateInfo(info, &easing_info_);
- TRACKRENDERER_LEAVE;
- return true;
-} // namespace trackrenderer
-
-bool AudioEasingController::SetInfo(const AudioEasingInfo& info) {
- TRACKRENDERER_ENTER;
- if (!internal::IsValidVolume(info.target_volume)) return false;
-
- std::lock_guard<std::mutex> pending_lock(pending_info_m_);
- internal::UpdateInfo(&pending_info_, &info);
- need_reset_ = true;
-
- if (pending_info_.duration == 0) {
- InterruptEasingThread_();
- volume_.store(pending_info_.target_volume);
- }
-
- if (is_stopped_.load() == true) {
- std::lock_guard<std::mutex> info_lock(current_info_m_);
- internal::UpdateInfo(&easing_info_, &pending_info_);
- elapsed_time_ms_.store(0);
- initial_volume_.store(volume_.load());
- need_reset_ = false;
- TRACKRENDERER_ERROR("elapsed time %u, initial volume %u",
- elapsed_time_ms_.load(), initial_volume_.load());
- }
- TRACKRENDERER_LEAVE;
- return true;
-}
-
-void AudioEasingController::AudioEasingStop() {
- TRACKRENDERER_ENTER;
- if (is_stopped_.load() == true) {
- TRACKRENDERER_ERROR("Stop : already paused");
- }
-
- InterruptEasingThread_();
- std::lock_guard<std::mutex> pending_lock(pending_info_m_);
- TRACKRENDERER_ERROR("before info lock");
- std::lock_guard<std::mutex> info_lock(current_info_m_);
- TRACKRENDERER_ERROR("after info lock");
- internal::UpdateInfo(&pending_info_, &easing_info_);
-
- TRACKRENDERER_LEAVE;
-}
-
-bool AudioEasingController::AudioEasingStart(GstElement* audiosink) {
- TRACKRENDERER_ENTER;
- if (audiosink == nullptr) {
- TRACKRENDERER_ERROR("audiosink is nullptr");
- return false;
- }
-
- bool need_lock_delay = NeedToWaitLockDelay_();
- InterruptEasingThread_();
-
- SetAudioGain_(audiosink, volume_.load());
-
- std::lock_guard<std::mutex> pending_lock(pending_info_m_);
- TRACKRENDERER_ERROR("before info lock");
- std::lock_guard<std::mutex> info_lock(current_info_m_);
- TRACKRENDERER_ERROR("after info lock");
- internal::UpdateInfo(&easing_info_, &pending_info_);
- auto volume = volume_.load();
- if (need_reset_) {
- elapsed_time_ms_.store(0);
- initial_volume_.store(volume);
- need_reset_ = false;
- TRACKRENDERER_ERROR("elapsed time %u, initial volume %u",
- elapsed_time_ms_.load(), initial_volume_.load());
- }
-
- if (easing_info_.target_volume == volume) return true;
-
- if (easing_info_.duration == 0) {
- SetAudioGain_(audiosink, easing_info_.target_volume);
- } else {
- easing_task_ = std::thread(&AudioEasingController::SetVolumeWithFade_, this,
- audiosink, need_lock_delay);
- }
- TRACKRENDERER_LEAVE;
- return true;
-}
-
-void AudioEasingController::SetVolumeWithFade_(GstElement* audiosink,
- bool need_lock_delay) {
- TRACKRENDERER_ENTER;
- if (audiosink == nullptr) return;
- is_stopped_.store(false);
-
- if (need_lock_delay) {
- TRACKRENDERER_ERROR("wait lock delay : %d", lock_delay_ms_);
- std::this_thread::sleep_for(std::chrono::microseconds(lock_delay_ms_));
- }
-
- TRACKRENDERER_ERROR("before info lock");
- std::unique_lock<std::mutex> info_lock(current_info_m_);
- TRACKRENDERER_ERROR("after info lock");
- const uint32_t target_volume = easing_info_.target_volume;
- const uint32_t duration_ms = easing_info_.duration;
- const AudioEasingType type = easing_info_.type;
- info_lock.unlock();
-
- float start_volume = static_cast<float>(initial_volume_.load());
- float delta = static_cast<float>(target_volume) - start_volume;
- uint32_t duration_us = internal::ConvertMsToMicroSec(duration_ms);
- const uint32_t interval = internal::GetMicroSecStepInterval(duration_us);
-
- if (type == AudioEasingType::kAudioEasingLinear) {
- delta = AdjustLinearTypeVolumeDelta_(delta, start_volume, target_volume);
- duration_us -= interval;
- }
-
- float set_volume = start_volume;
- auto elapsed_time_us = internal::ConvertMsToMicroSec(elapsed_time_ms_.load());
- const uint32_t init_elapsed_time_us = elapsed_time_us;
- TRACKRENDERER_ERROR("start_volume %f / cur volume %u, elapsed us time %u",
- set_volume, volume_.load(), elapsed_time_us);
-
- TRACKRENDERER_ERROR(
- "Ease Duration(%u us), Ease Volume Delta(%f), Ease Step Interval(%u us), "
- "Ease Type(%d)",
- duration_us, delta, interval, static_cast<int>(type));
- auto begin = std::chrono::system_clock::now();
-
- const AudioEasingInfo setup_info = {target_volume, duration_ms, type};
- SetEasingStartProperty_(audiosink, setup_info);
-
- while (duration_us) {
- if (is_ease_interrupt_) {
- TRACKRENDERER_ERROR("interrupt break");
- SetEasingStopProperty_(audiosink);
- is_stopped_.store(true);
- return;
- }
-
- set_volume =
- CalculateVolume_(static_cast<float>(elapsed_time_us), start_volume,
- delta, static_cast<float>(duration_us), type);
-
- SetAudioGain_(audiosink, static_cast<uint32_t>(set_volume));
- auto real_elapsed_time =
- internal::GetMicroSecElapsedEasingTime(begin) + init_elapsed_time_us;
-
- if (elapsed_time_us >= duration_us) {
- break;
- }
- elapsed_time_us += interval;
- elapsed_time_ms_.store(internal::ConvertMicroSecToMs(elapsed_time_us));
-
- internal::WaitGap(elapsed_time_us, real_elapsed_time);
- }
-
- if (static_cast<uint32_t>(set_volume) != target_volume) {
- TRACKRENDERER_ERROR("diff set volume & target volume");
- auto real_elapsed_time =
- internal::GetMicroSecElapsedEasingTime(begin) + init_elapsed_time_us;
-
- elapsed_time_us += interval;
- elapsed_time_ms_.store(internal::ConvertMicroSecToMs(elapsed_time_us));
-
- internal::WaitGap(internal::ConvertMsToMicroSec(duration_ms),
- real_elapsed_time);
-
- SetAudioGain_(audiosink, target_volume);
- }
- SetEasingStopProperty_(audiosink);
- is_stopped_.store(true);
-
- auto final_elapsed_time =
- internal::GetMicroSecElapsedEasingTime(begin) + init_elapsed_time_us;
-
- TRACKRENDERER_ERROR(
- "Final target volume [%d], start volume [%f], elapsedTime[%d ms /%d ms], "
- "final_elapsed_time [%d us]",
- target_volume, start_volume, elapsed_time_ms_.load(), duration_ms,
- final_elapsed_time);
-
- TRACKRENDERER_LEAVE;
- return;
-}
-
-bool AudioEasingController::NeedToWaitLockDelay_() {
- return easing_task_.joinable() ? FALSE : TRUE;
-}
-
-void AudioEasingController::InterruptEasingThread_() {
- TRACKRENDERER_ENTER;
-
- std::lock_guard<std::mutex> lock(easing_m_);
-
- is_ease_interrupt_ = true;
- if (easing_task_.joinable()) {
- TRACKRENDERER_ERROR("join before");
- easing_task_.join();
- TRACKRENDERER_ERROR("join after");
- }
-
- is_ease_interrupt_ = false;
- TRACKRENDERER_LEAVE;
-}
-
-float AudioEasingController::AdjustLinearTypeVolumeDelta_(float delta,
- float start,
- int target) {
- int i;
- int volume = target;
- int last_gain = kVolumeToGainIndexTable[volume];
-
- if (delta >= 0) {
- for (i = volume - 1; i >= 0; i--) {
- if (kVolumeToGainIndexTable[i] != last_gain) {
- break;
- }
- }
- } else {
- for (i = volume + 1; i < kMaxVolumeIndex; i++) {
- if (kVolumeToGainIndexTable[i] != last_gain) {
- break;
- }
- }
- }
-
- volume = i;
- delta = static_cast<float>(volume) - start;
-
- return delta;
-}
-
-float AudioEasingController::CalculateVolume_(float t, float b, float delta,
- float d, AudioEasingType type) {
- float volume;
- switch (type) {
- case AudioEasingType::kAudioEasingIncubic: {
- TRACKRENDERER_INFO("INCUBIC Ease");
- t /= d;
- volume = delta * t * t * t + b;
- } break;
- case AudioEasingType::kAudioEasingOutcubic: {
- TRACKRENDERER_INFO("OUTCUBIC Ease");
- t = t / d - 1.0f;
- volume = delta * (t * t * t + 1.0f) + b;
- } break;
- case AudioEasingType::kAudioEasingLinear:
- default: {
- TRACKRENDERER_INFO("LINEAR Ease");
- volume = (delta * t) / d + b;
- } break;
- }
-
- if (delta > 0) {
- volume += 0.5;
- }
-
- return volume;
-}
-
-bool AudioEasingController::SetAudioGain_(GstElement* audiosink,
- uint32_t volume) {
- TRACKRENDERER_ENTER;
- if (audiosink == nullptr) return false;
- if (volume > kMaxVolumeIndex) return false;
-
- int gain = kVolumeToGainIndexTable[volume];
- g_object_set(G_OBJECT(audiosink), "device-volume", gain, NULL);
-
- volume_.store(volume);
- TRACKRENDERER_INFO("gain : %d / volume : %u", gain, volume);
- TRACKRENDERER_LEAVE;
- return true;
-}
-
-void AudioEasingController::SetEasingStartProperty_(
- GstElement* audiosink, const AudioEasingInfo& setup_info) {
- TRACKRENDERER_ENTER;
- if (audiosink == nullptr) return;
-
- const uint32_t target_volume =
- kVolumeToGainIndexTable[setup_info.target_volume];
- const uint32_t duration = setup_info.duration - elapsed_time_ms_.load();
-
- const AudioEasingInfo start_info = {target_volume, duration, setup_info.type};
- SetEasingInfoProperty_(audiosink, start_info);
-
- TRACKRENDERER_LEAVE;
- return;
-}
-
-void AudioEasingController::SetEasingStopProperty_(GstElement* audiosink) {
- TRACKRENDERER_ENTER;
- if (audiosink == nullptr) return;
-
- const uint32_t target_volume = kVolumeToGainIndexTable[volume_.load()];
- const AudioEasingInfo stop_info = {target_volume, static_cast<uint32_t>(-1),
- AudioEasingType::kAudioEasingLinear};
- SetEasingInfoProperty_(audiosink, stop_info);
-
- TRACKRENDERER_LEAVE;
- return;
-}
-
-void AudioEasingController::SetEasingInfoProperty_(
- GstElement* audiosink, const AudioEasingInfo& info) {
- if (audiosink == nullptr) return;
-
- auto easing_info = gstguard::make_guard(gst_structure_new(
- "easing-info", "volume", G_TYPE_UINT, info.target_volume, "duration",
- G_TYPE_INT, info.duration, "type", G_TYPE_UINT,
- static_cast<uint32_t>(info.type), NULL));
- g_object_set(G_OBJECT(audiosink), "audio-easing-info", easing_info.get(),
- NULL);
- return;
-}
-
-} // namespace trackrenderer
-} // namespace plusplayer
}
bool CheckPcmS16Le(const Track& track) {
- return ((track.is_signed && track.sample_format == 16 &&
- track.endianness == kLittleEndian) ||
- (track.codec_tag == "S16LE"));
+ return track.is_signed && track.sample_format == 16 &&
+ track.endianness == kLittleEndian;
}
void FillPcmS16Le(const GstCapsWrapper& caps, const Track& track) {
caps.SetValue("layout", G_TYPE_STRING, "interleaved");
caps.SetValue("bpp", G_TYPE_INT, 16);
caps.SetValue("endianness", G_TYPE_INT, 1234);
caps.SetValue("signed", G_TYPE_BOOLEAN, true);
- caps.SetValue("block_align", G_TYPE_INT, track.block_align);
}
bool CheckPcmS16Be(const Track& track) {
void FillDolby(const GstCapsWrapper& caps, const Track& track) {
caps.SetValue("framed", G_TYPE_BOOLEAN, true);
caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
- caps.SetValue("bpp", G_TYPE_INT, track.bits_per_sample);
-}
-
-/* =========================================
- * audio/x-adpcm
- * =========================================
- */
-void FillAdpcm(const GstCapsWrapper& caps, const Track& track) {
- caps.SetValue("block_align", G_TYPE_INT, track.block_align);
- caps.SetValue("layout", G_TYPE_STRING, track.layout.c_str());
-}
-/* =========================================
- * audio/x-wma
- * =========================================
- */
-void FillWma(const GstCapsWrapper& caps, const Track& track) {
- caps.SetValue("block_align", G_TYPE_INT, track.block_align);
- caps.SetValue("wmaversion", G_TYPE_INT, track.version);
- caps.SetValue("bpp", G_TYPE_INT, track.bits_per_sample);
- if (!track.codec_tag.empty())
- caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
- else
- caps.SetValue("format", G_TYPE_STRING,
- (track.version == 1) ? "0160" : "0161");
-
- caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
-}
-/* =========================================
- * audio/x-pn-realaudio
- * =========================================
- */
-void FillRealAudio(const GstCapsWrapper& caps, const Track& track) {
- caps.SetValue("flavor", G_TYPE_INT, track.flavor);
- caps.SetValue("leaf_size", G_TYPE_INT, track.block_align);
- caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
-}
-
-/* =========================================
- * audio/x-vorbis
- * =========================================
- */
-void FillVorbis(const GstCapsWrapper& caps, const Track& track) {
- caps.SetValue("block_align", G_TYPE_INT, track.block_align);
- caps.SetValue("bpp", G_TYPE_INT, track.bits_per_sample);
- caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
- caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
}
} // namespace audio
track.framerate_den);
}
-// LCOV_EXCL_START
/* =========================================
* video/mpeg
* =========================================
void FillMpeg(const GstCapsWrapper& caps, const Track& track) {
caps.SetValue("mpegversion", G_TYPE_INT, track.version);
caps.SetValue("systemstream", G_TYPE_BOOLEAN, false);
- if (!track.codec_tag.empty())
- caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
}
/* =========================================
*/
void FillWmv(const GstCapsWrapper& caps, const Track& track) {
caps.SetValue("wmvversion", G_TYPE_INT, track.version);
- if (!track.codec_tag.empty())
- caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
- else
- switch (track.version) {
- case 1:
- caps.SetValue("format", G_TYPE_STRING, "WMV1");
- break;
- case 2:
- caps.SetValue("format", G_TYPE_STRING, "WMV2");
- break;
- case 3:
- caps.SetValue("format", G_TYPE_STRING, "WMV3");
- break;
- }
}
/* =========================================
// to check current is VP9 or not.
caps.SetValue("VP9", G_TYPE_INT, 1);
}
-/* =========================================
- * video/x-raw
- * =========================================
- */
-void FillVideoRaw(const GstCapsWrapper& caps, const Track& track) {
- caps.SetValue("format", G_TYPE_STRING, "STV1");
-}
-/* =========================================
- * video/x-vp6
- * =========================================
- */
-void FillVP6(const GstCapsWrapper& caps, const Track& track) {
- if (!track.codec_tag.empty())
- caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
-}
-/* =========================================
- * video/x-jpeg
- * =========================================
- */
-void FillJpeg(const GstCapsWrapper& caps, const Track& track) {
- if (!track.codec_tag.empty())
- caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
-}
-// LCOV_EXCL_STOP
} // namespace video
bool AlwaysPass(const Track& track) { return true; }
{
{track::AlwaysPass, track::audio::FillDolby},
}},
- {"audio/x-adpcm",
- {
- {track::AlwaysPass, track::audio::FillAdpcm},
- }},
- {"audio/x-wma",
- {
- {track::AlwaysPass, track::audio::FillWma},
- }},
- {"audio/x-pn-realaudio",
- {
- {track::AlwaysPass, track::audio::FillRealAudio},
- }},
- {"audio/x-vorbis",
- {
- {track::AlwaysPass, track::audio::FillVorbis},
- }},
{"video/mpeg",
{
{track::AlwaysPass, track::video::FillMpeg},
{
{track::AlwaysPass, track::video::FillVP9},
}},
- {"video/x-raw",
- {
- {track::AlwaysPass, track::video::FillVideoRaw},
- }},
- {"video/x-vp6",
- {
- {track::AlwaysPass, track::video::FillVP6},
- }},
- {"video/x-jpeg",
- {
- {track::AlwaysPass, track::video::FillJpeg},
- }},
};
} // namespace trackrenderer
#include "Elementary.h"
#include "glib-object.h"
#include "tizen-extension-client-protocol.h"
+#include "wayland-client.h"
+
#include "trackrenderer/core/gstobject_guard.h"
#include "trackrenderer/core/utils/log.h"
-#include "wayland-client.h"
namespace plusplayer {
}
static const wl_registry_listener registry_listener = {
- GlobalHandle, NULL
+ GlobalHandle,
};
bool GetWindowGeometry(Evas_Object* obj, int* x, int* y, int* width,
}
wl_registry_add_listener(wlclient.registry, ®istry_listener, &wlclient);
- TRACKRENDERER_INFO("wl_display_roundtrip_queue()");
wl_display_roundtrip_queue(wlclient.display, queue);
if (!wlclient.surface) {
return kInvalidSurfaceId;
}
- TRACKRENDERER_INFO("tizen_surface_get_tizen_resource()");
wlclient.resource =
tizen_surface_get_tizen_resource(wlclient.surface, surface);
if (!wlclient.resource) {
return kInvalidSurfaceId;
}
- TRACKRENDERER_INFO("tizen_resource_add_listener()");
unsigned int surface_id = kInvalidSurfaceId;
tizen_resource_add_listener(wlclient.resource, &tizen_resource_listener,
&surface_id);
- TRACKRENDERER_INFO("wl_display_roundtrip_queue()");
wl_display_roundtrip_queue(wlclient.display, queue);
if (surface_id <= 0) {
return kInvalidSurfaceId;
bool Display::SetDisplay(const DisplayType& type, Evas_Object* obj) {
assert(obj && "obj should not be null");
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
if (type == DisplayType::kNone) {
unsigned int surface_id = 0;
long x = 0, y = 0, w = 0, h = 0;
const std::string obj_type(evas_object_type_get(obj));
if (!obj_type.c_str()) {
assert(0 && "object type is null");
- TRACKRENDERER_ERROR_P(this, "object type is null");
+ TRACKRENDERER_ERROR("object type is null");
return false;
}
int x, y, w, h;
bool ret = internal::GetWindowGeometry(obj, &x, &y, &w, &h);
if (!ret) {
- TRACKRENDERER_ERROR_P(this, "Fail GetWindowGeometry");
+ TRACKRENDERER_ERROR("Fail GetWindowGeometry");
return false;
}
Ecore_Evas* ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
Ecore_Wl2_Window* wl_window = ecore_evas_wayland2_window_get(ee);
if (!wl_window) {
- TRACKRENDERER_ERROR_P(this, "elm_win_wl_window_get() failed");
+ TRACKRENDERER_ERROR("elm_win_wl_window_get() failed");
return false;
}
- wl_surface* surface = GetWlSurface_(wl_window);
- return SetDisplay_(type, surface, x, y, w, h);
+ return SetDisplay_(type, wl_window, x, y, w, h);
} else {
// TODO(js4716.chun) :
// else if (type == PLAYER_DISPLAY_TYPE_EVAS &&
// !strcmp(object_type, "image"))
assert(obj && "not support yet!");
}
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
-wl_surface* Display::GetWlSurface_(Ecore_Wl2_Window* ecore_wl2_window) {
- /*
- app have to call ecore_wl2_window_video_surface_create() for sync issue
- between video and graphic. then player can get surface id from
- ecore_wl2_window_video_surface_get().
- */
- wl_surface* surface =
- (wl_surface*)ecore_wl2_window_video_surface_get(ecore_wl2_window);
- if (surface) {
- TRACKRENDERER_INFO_P(this,
- "sync support: get surface id from "
- "ecore_wl2_windoe_video_surface_get()");
- has_parent_surface_ = true;
- } else {
- // EAPI struct wl_surface *
- // ecore_wl2_window_surface_get(Ecore_Wl2_Window * win)
- surface = ecore_wl2_window_surface_get(ecore_wl2_window);
- }
- return surface;
-}
-
-// LCOV_EXCL_START
bool Display::SetDisplay(const DisplayType& type,
Ecore_Wl2_Window* ecore_wl2_window, const int x,
const int y, const int w, const int h) {
assert(ecore_wl2_window && "ecore_wl2_window should not be null");
assert((type == DisplayType::kOverlay) && "not support yet!");
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
if (type == DisplayType::kNone) {
unsigned int surface_id = 0;
int x_ = 0, y_ = 0, w_ = 0, h_ = 0;
BOOST_SCOPE_EXIT(void) { ecore_thread_main_loop_end(); }
BOOST_SCOPE_EXIT_END
- wl_surface* surface = GetWlSurface_(ecore_wl2_window);
- return SetDisplay_(type, surface, x, y, w, h);
+ return SetDisplay_(type, ecore_wl2_window, x, y, w, h);
}
-// LCOV_EXCL_STOP
-
-bool Display::SetDisplaySubsurface(const DisplayType& type,
- Ecore_Wl2_Subsurface* ecore_wl2_subsurface,
- const int x, const int y, const int w,
- const int h) {
- assert(ecore_wl2_subsurface && "ecore_wl2_subsurface should not be null");
- assert((type == DisplayType::kOverlay) && "not support yet!");
-
- TRACKRENDERER_ENTER_P(this);
- if (type == DisplayType::kNone) {
- unsigned int surface_id = 0;
- int x_ = 0, y_ = 0, w_ = 0, h_ = 0;
- SetDisplay(type, surface_id, x_, y_, w_, h_);
- return false;
- }
- ecore_thread_main_loop_begin();
-
- BOOST_SCOPE_EXIT(void) { ecore_thread_main_loop_end(); }
- BOOST_SCOPE_EXIT_END
-
- wl_surface* surface = (wl_surface*)ecore_wl2_subsurface_native_surface_get(
- ecore_wl2_subsurface);
- has_parent_surface_ = true;
- return SetDisplay_(type, surface, x, y, w, h);
-}
-
-bool Display::SetDisplay_(const DisplayType& type, wl_surface* surface,
- const int x, const int y, const int w, const int h) {
+bool Display::SetDisplay_(const DisplayType& type,
+ Ecore_Wl2_Window* ecore_wl2_window, const int x,
+ const int y, const int w, const int h) {
+ // EAPI struct wl_surface *
+ // ecore_wl2_window_surface_get(Ecore_Wl2_Window * win)
+ wl_surface* surface = ecore_wl2_window_surface_get(ecore_wl2_window);
if (!surface) {
- TRACKRENDERER_ERROR_P(this, "ecore_wl_window_surface_get() failed");
+ TRACKRENDERER_ERROR("ecore_wl_window_surface_get() failed");
return false;
}
Ecore_Wl2_Display* wl2_display = ecore_wl2_connected_display_get(NULL);
wl_display* display = ecore_wl2_display_get(wl2_display);
if (!display) {
- TRACKRENDERER_ERROR_P(this, "ecore_wl_display_get() failed");
+ TRACKRENDERER_ERROR("ecore_wl_display_get() failed");
return false;
}
unsigned int surfaceid = internal::GetSurfaceId(surface, display);
if (surfaceid == kInvalidSurfaceId) {
- TRACKRENDERER_ERROR_P(this, "Can't get surface id!");
+ TRACKRENDERER_ERROR("Can't get surface id!");
return false;
}
// x = 0;
// y = 0;
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return SetDisplay(type, surfaceid, x, y, w, h);
}
bool Display::SetDisplay(const DisplayType& type, const uint32_t surface_id,
const int x, const int y, const int w, const int h) {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
// TODO(euna7.ko) State should not be idle.
// unsigned int pre_surface_id = surface_id_; // for backup previouse info.
std::lock_guard<std::mutex> lock(settings_mutex_);
- TRACKRENDERER_INFO_P(this,
- "type: %d, surface_id: %d, x(%d) y(%d) w(%d) h(%d)",
- static_cast<int>(type), surface_id, x, y, w, h);
+ TRACKRENDERER_INFO("type: %d, surface_id: %d, x(%d) y(%d) w(%d) h(%d)",
+ static_cast<int>(type), surface_id, x, y, w, h);
if (type == DisplayType::kNone) { /* Null serface */
surface_id_ = 0;
} else if (type == DisplayType::kOverlay) {
surface_id_ = surface_id;
} else { // plusplayer don't handle of Evas case.
- TRACKRENDERER_ERROR_P(this, "Not Support Surface type");
+ TRACKRENDERER_ERROR("Not Support Surface type");
return false;
}
// TODO(euna7.ko) if We need to change window, how can we update it??
// display_->Update(pipeline_->video_sink);
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
bool Display::SetDisplayRoi(const Geometry& roi) {
std::lock_guard<std::mutex> lock(settings_mutex_);
if (mode_ != DisplayMode::kDstRoi) {
- TRACKRENDERER_ERROR_P(this, "DisplayMode is not Roi!");
+ TRACKRENDERER_ERROR("DisplayMode is not Roi!");
return false;
}
roi_ = roi;
return true;
}
-bool Display::ResizeRenderRect(const RenderRect& rect) {
- std::lock_guard<std::mutex> lock(settings_mutex_);
- //x,y should be set with 0 to avoid double calculation at TDM side
- window_.x = 0;
- window_.y = 0;
- window_.w = rect.w;
- window_.h = rect.h;
- return true;
-}
-
-void Display::GetDisplayCropArea(CropArea* area) {
- std::lock_guard<std::mutex> lock(settings_mutex_);
- *area = scale_;
-}
-
bool Display::Update(GstElement* videosink) {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
if (videosink == nullptr) {
assert(0);
return false;
// - gst_video_overlay_set_window_handle (GstVideoOverlay * overlay
// , guintptr handle)
if (type_ == DisplayType::kOverlay && surface_id_ != 0) { // waylandsink
- if (has_parent_surface_)
- g_object_set(G_OBJECT(videosink), "has-parent-surface", true, NULL);
- TRACKRENDERER_DEBUG_P(this, "serfaceid: %d, x: %d, y: %d, w: %d, h: %d",
- surface_id_, window_.x, window_.y, window_.w,
- window_.h);
- gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(videosink),
+ TRACKRENDERER_DEBUG("serfaceid: %d, x: %d, y: %d, w: %d, h: %d",
+ surface_id_, window_.x, window_.y, window_.w,
+ window_.h);
+ gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(videosink),
surface_id_);
gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(videosink),
window_.x, window_.y, window_.w,
window_.h);
- TRACKRENDERER_DEBUG_P(this, "mode: %d, visible: %d, rotate: %d",
- static_cast<int>(mode_), visible_,
- static_cast<int>(rotate_));
- g_object_set(G_OBJECT(videosink), "seamless-resolution-change", true, NULL);
+ TRACKRENDERER_DEBUG("mode: %d, visible: %d, rotate: %d",
+ static_cast<int>(mode_), visible_,
+ static_cast<int>(rotate_));
int mode_value = internal::ConvertDisplayModeValue(mode_);
int rotate_value = static_cast<int>(rotate_);
g_object_set(G_OBJECT(videosink), "display-geometry-method", mode_value,
"visible", visible_, "rotate", rotate_value, nullptr);
- g_object_set(G_OBJECT(videosink), "display-src-x-ratio", scale_.scale_x,
- "display-src-y-ratio", scale_.scale_y, "display-src-w-ratio",
- scale_.scale_w, "display-src-h-ratio", scale_.scale_h,
- nullptr);
- g_object_set(G_OBJECT(videosink), "video-quality-mode", qualitymode_,
- nullptr);
-
- if (video_quality_info_caps_.get() != nullptr) {
- g_object_set(G_OBJECT(videosink), "video-quality-info",
- video_quality_info_caps_.get(), NULL);
- video_quality_info_caps_.reset();
- }
if (mode_ == DisplayMode::kDstRoi) {
if (roi_.w != 0 && roi_.h != 0) {
- TRACKRENDERER_ERROR_P(this, "Roi > x[%d] y[%d] w[%d] h[%d]", roi_.x,
- roi_.y, roi_.w, roi_.h);
- g_object_set(G_OBJECT(videosink), "dst-roi-x", roi_.x, "dst-roi-y",
- roi_.y, "dst-roi-w", roi_.w, "dst-roi-h", roi_.h, nullptr);
+ TRACKRENDERER_ERROR("Roi > x[%d] y[%d] w[%d] h[%d]", roi_.x, roi_.y,
+ roi_.w, roi_.h);
+ g_object_set(G_OBJECT(videosink), "display-roi-x", roi_.x, "display-roi-y",
+ roi_.y, "display-roi-width", roi_.w, "display-roi-height", roi_.h, nullptr);
}
}
}
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
bool Display::UpdateVisible(GstElement* videosink) {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
if (videosink == nullptr) {
assert(0);
return false;
std::lock_guard<std::mutex> lock(settings_mutex_);
if (type_ == DisplayType::kOverlay && surface_id_ != 0) { // waylandsink
- TRACKRENDERER_DEBUG_P(this, "visible: %d", visible_);
+ TRACKRENDERER_DEBUG("visible: %d", visible_);
g_object_set(G_OBJECT(videosink), "visible", visible_, nullptr);
}
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
gstguard::make_guard(gst_caps_copy(video_quality_info_caps));
}
-bool Display::UpdateCropArea(GstElement* videosink) {
- TRACKRENDERER_ENTER_P(this);
- if (videosink == nullptr) {
- assert(0);
- return false;
- }
-
- std::lock_guard<std::mutex> lock(settings_mutex_);
-
- if (type_ == DisplayType::kOverlay && surface_id_ != 0) { // waylandsink
- g_object_set(G_OBJECT(videosink), "display-src-x-ratio", scale_.scale_x,
- "display-src-y-ratio", scale_.scale_y, "display-src-w-ratio",
- scale_.scale_w, "display-src-h-ratio", scale_.scale_h,
- nullptr);
- }
- TRACKRENDERER_LEAVE_P(this);
- return true;
-}
-
void Display::SetDisplayMode(const DisplayMode& mode) { mode_ = mode; }
void Display::SetDisplayRotate(const DisplayRotation& rotate) {
#include "trackrenderer/core/gst_utils.h"
#include "trackrenderer/core/gstobject_guard.h"
#include "trackrenderer/core/utils/log.h"
-// LCOV_EXCL_START
+
namespace plusplayer {
namespace trackrenderer {
return internal::HandleGstError(error.get());
}
-void HandleErrorMsg(GstMessage* message, gchar** error_msg) {
- if (message == nullptr) return;
-
- GError* p_error = nullptr;
- gst_message_parse_error(message, &p_error, error_msg);
- auto error = gstguard::make_guard(p_error);
- if (error == nullptr || *error_msg == nullptr) return;
-
- TRACKRENDERER_DEBUG("ERROR is posting. from %s / %s \n>> %s \n>> %s",
- gst_util::GetKlass(message),
- gst_util::GetElementName(message), error->message, *error_msg);
- return;
-}
-
-
} // namespace trackrenderer
} // namespace plusplayer
-// LCOV_EXCL_STOP
-
namespace gst_util {
-void ShowStateChangedMsg(GstMessage* msg, void* id) {
+void ShowStateChangedMsg(GstMessage* msg) {
GstState old_state = GST_STATE_VOID_PENDING;
GstState new_state = GST_STATE_VOID_PENDING;
GstState pending_state = GST_STATE_VOID_PENDING;
gst_message_parse_state_changed(msg, &old_state, &new_state, &pending_state);
- TRACKRENDERER_ERROR_P(id,
+ TRACKRENDERER_ERROR(
"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) {
+void SetGstStateToNull(GstElement* pipeline) {
if (!pipeline) return;
GstStateChangeReturn ret;
ret = gst_element_set_state(pipeline, GST_STATE_NULL);
if (ret == GST_STATE_CHANGE_FAILURE) {
- TRACKRENDERER_ERROR_P(id, "Set State to NULL failed");
+ TRACKRENDERER_ERROR("Set State to NULL failed");
}
}
-// LCOV_EXCL_START
const gchar* GetElementName(const GstMessage* msg) {
GstElement* src_element = GST_ELEMENT_CAST(msg->src);
if (!src_element) return nullptr;
char** pargv = argv;
gst_init(&argc, &pargv);
}
-// LCOV_EXCL_STOP
+
} // namespace gst_util
} // namespace trackrenderer
#include "trackrenderer/core/gstcaps_builder.h"
#include <string>
-#include <algorithm>
#include "trackrenderer/core/caps_recipes.h"
#include "trackrenderer/core/pipeline.hpp"
namespace internal {
-constexpr guint kMaxAudioChannels = 64;
-
static GstBuffer* MakeGstBufferWithCodecData(const std::shared_ptr<char>& data,
int len) {
constexpr int kMaxLen = 1024 * 1024;
}
}
+static void FillStreamFormat(const GstCapsWrapper& caps, const Track& track) {
+ if (!track.stream_format.empty()) {
+ caps.SetValue("stream-format", G_TYPE_STRING, track.stream_format.c_str());
+ }
+ if (!track.alignment.empty()) {
+ caps.SetValue("alignment", G_TYPE_STRING, track.alignment.c_str());
+ }
+ caps.SetValue("adaptive-streaming", G_TYPE_BOOLEAN, true);
+}
+
+static void FillDrmInfo(const GstCapsWrapper& caps, const Track& track) {
+ if (!track.original_media_type.empty())
+ caps.SetValue("original-media-type", G_TYPE_STRING, track.original_media_type.c_str());
+
+ if (!track.protection_system.empty())
+ caps.SetValue("protection-system", G_TYPE_STRING, track.protection_system.c_str());
+}
+
static void FillStreamType(const GstCapsWrapper& caps, const Track& track) {
if (track.streamtype.empty()) return;
caps.SetValue("stream-type", G_TYPE_STRING, track.streamtype.c_str());
MakeGstBufferWithCodecData(track.codec_data, track.codec_data_len);
if (codec_data == nullptr) return;
caps.SetValue("codec_data", GST_TYPE_BUFFER, codec_data);
+ gst_buffer_unref(codec_data);
}
static void FillSecureField(const GstCapsWrapper& caps, const Track& track) {
static void FillChannelMaskField(const GstCapsWrapper& caps,
const Track& track) {
- GstAudioChannelPosition position[kMaxAudioChannels];
+ GstAudioChannelPosition position[64];
guint64 channel_mask = 0;
- guint nchannels = std::min(static_cast<guint>(track.channels),
- kMaxAudioChannels);
+ guint nchannels = track.channels;
if (nchannels <= 2) return;
if (nchannels == 4) {
position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
} else {
guint i;
for (i = 0; i < nchannels; i++) {
- position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+ if (i <= 63) position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
}
}
guint j;
FillDefaultValue_(caps, track);
internal::FillStreamType(caps, track);
internal::FillCodecData(caps, track);
+ internal::FillStreamFormat(caps, track);
+ internal::FillDrmInfo(caps, track);
+ internal::FillSecureField(caps, track);
+ internal::FillChannelMaskField(caps, track);
+
+ caps.PrintCapsString();
+
+ return caps;
+}
+
+GstCapsWrapper GstCapsBuilder::BuildOrgMediaType(const Track& track, bool is_drm) {
+ const std::string media_type = internal::GetMediaType(track);
+ const std::string caps_name = internal::GetCapsName(track.original_media_type, is_drm);
+
+ TRACKRENDERER_DEBUG("media_type[%s] caps_name[%s]", media_type.c_str(),
+ caps_name.c_str());
+
+ GstCapsWrapper caps(caps_name);
+
+ auto filler = FindCapsFiller_(track, media_type);
+ if (filler != nullptr) filler(caps, track);
+
+ FillDefaultValue_(caps, track);
+ internal::FillStreamType(caps, track);
+ internal::FillCodecData(caps, track);
+
+ internal::FillStreamFormat(caps, track);
+
internal::FillSecureField(caps, track);
internal::FillChannelMaskField(caps, track);
void GstSignalHolder::DeleteAll() {
std::lock_guard<std::mutex> guard(item_lock_);
- TRACKRENDERER_INFO("num of signals[ %d ]", signal_list_.size());
+ TRACKRENDERER_INFO("num of signals[ %" G_GSIZE_FORMAT " ]", signal_list_.size());
signal_list_.clear();
}
+++ /dev/null
-//
-// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_AUDIOEASING_CONTROLLER_H__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_AUDIOEASING_CONTROLLER_H__
-
-#include <gst/gstelement.h>
-
-#include <atomic>
-#include <boost/core/noncopyable.hpp>
-#include <mutex>
-#include <string>
-#include <thread>
-
-#include "trackrenderer/core/audioeasinginfo.h"
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-class AudioEasingController : private boost::noncopyable {
- public:
- explicit AudioEasingController(uint32_t init_volume,
- uint32_t init_elapsed_time,
- const AudioEasingInfo& init_info);
- ~AudioEasingController();
- bool AudioEasingStart(GstElement* audiosink);
- void AudioEasingStop();
- bool SetInfo(const AudioEasingInfo& info);
- bool GetInfo(uint32_t* current_volume, uint32_t* elapsed_time,
- AudioEasingInfo* info);
- int GetGainFromVolume(uint32_t volume);
-
- private:
- bool SetAudioGain_(GstElement* audiosink, uint32_t volume);
- float CalculateVolume_(float t, float b, float delta, float d,
- AudioEasingType type);
- float AdjustLinearTypeVolumeDelta_(float delta, float start, int target);
- void InterruptEasingThread_();
- void SetVolumeWithFade_(GstElement* audiosink, bool need_lock_delay);
- void SetEasingStartProperty_(GstElement* audiosink,
- const AudioEasingInfo& setup_info);
- void SetEasingStopProperty_(GstElement* audiosink);
- void SetEasingInfoProperty_(GstElement* audiosink,
- const AudioEasingInfo& info);
- bool NeedToWaitLockDelay_();
-
- private:
- bool is_ease_interrupt_ = false;
- bool need_reset_ = false;
- // temporary fixed value. lock delay have dependency with chipset.
- uint32_t lock_delay_ms_ = 150000;
- std::atomic<uint32_t> initial_volume_;
- std::atomic<uint32_t> volume_;
- std::atomic<uint32_t> elapsed_time_ms_;
- std::atomic<bool> is_stopped_;
- AudioEasingInfo easing_info_ = {100, 0, AudioEasingType::kAudioEasingNone};
- AudioEasingInfo pending_info_ = {100, 0, AudioEasingType::kAudioEasingNone};
- std::thread easing_task_;
-
- std::mutex pending_info_m_;
- std::mutex current_info_m_;
- std::mutex easing_m_;
- std::mutex state_m_;
-};
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_AUDIOEASING_CONTROLLER_H__
+++ /dev/null
-//
-// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DEFAULT_POLICY_HPP__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DEFAULT_POLICY_HPP__
-
-#include "trackrenderer/audio_controller/resyncaudio_policy.h"
-#include "trackrenderer/core/utils/log.h"
-
-namespace plusplayer {
-namespace trackrenderer {
-namespace resync_audio {
-class DefaultPolicy : public ResyncAudioPolicy {
- public:
- DefaultPolicy() = default;
- virtual ~DefaultPolicy() = default;
-
- public:
- virtual bool Resync(PipelinePtr& pipeline) override {
- TRACKRENDERER_ENTER
- return pipeline->SetProperty(Elements::kSinkAudio, "audio-swap", TRUE);
- }
-};
-} // namespace resync_audio
-} // namespace trackrenderer
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DEFAULT_POLICY_HPP__
+++ /dev/null
-//
-// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DUMMY_POLICY_HPP__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DUMMY_POLICY_HPP__
-
-#include "trackrenderer/audio_controller/resyncaudio_policy.h"
-#include "trackrenderer/core/utils/log.h"
-
-namespace plusplayer {
-namespace trackrenderer {
-namespace resync_audio {
-class DummyPolicy : public ResyncAudioPolicy {
- public:
- DummyPolicy() = default;
- virtual ~DummyPolicy() = default;
-
- public:
- virtual bool Resync(PipelinePtr& pipeline) override {
- TRACKRENDERER_ENTER
- return true;
- }
-};
-} // namespace resync_audio
-} // namespace trackrenderer
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DUMMY_POLICY_HPP__
+++ /dev/null
-//
-// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_POLICIES_H__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_POLICIES_H__
-
-#include "trackrenderer/audio_controller/resyncaudio/default_policy.hpp"
-#include "trackrenderer/audio_controller/resyncaudio/dummy_policy.hpp"
-#include "trackrenderer/audio_controller/resyncaudio/swdecoder_policy.hpp"
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_POLICIES_H__
\ No newline at end of file
+++ /dev/null
-//
-// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
-//
-// LCOV_EXCL_START
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_SWDECODER_POLICY_HPP__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_SWDECODER_POLICY_HPP__
-
-#include <boost/scope_exit.hpp>
-#include <mutex>
-#include <string>
-
-#include "trackrenderer/audio_controller/resyncaudio_policy.h"
-#include "trackrenderer/core/utils/log.h"
-
-namespace plusplayer {
-namespace trackrenderer {
-namespace resync_audio {
-class SwDecoderPolicy : public ResyncAudioPolicy {
- public:
- explicit SwDecoderPolicy(const std::uint64_t& rstarttime,
- const double& playback_rate)
- : rendering_start_time_(rstarttime), playback_rate_(playback_rate) {}
- virtual ~SwDecoderPolicy() = default;
-
- public:
- virtual bool Resync(PipelinePtr& pipeline) override {
- TRACKRENDERER_ENTER
-
- Pipeline<Elements>::Pad padprobe;
- pipeline->PeerPadAddProbe(
- Elements::kSinkAudio, kPadBlockProbeId_.c_str(), "sink", kPadProbeType_,
- GstSrcPadProbeIdleAndBlockCb_, &padprobe, nullptr);
-
- BOOST_SCOPE_EXIT(&pipeline, &kPadBlockProbeId_) {
- if (pipeline->PadRemoveProbe(kPadBlockProbeId_.c_str()) == false) {
- TRACKRENDERER_WARN("[WARNING] PadRemoveProbe failed");
- }
- }
- BOOST_SCOPE_EXIT_END
-
- TRACKRENDERER_INFO("Wait for Pad Idle!");
- {
- std::unique_lock<std::mutex> lk(padprobe.m);
- padprobe.cv.wait(lk, [&padprobe]() { return padprobe.is_idle; });
- }
- TRACKRENDERER_INFO("Wait for Pad Idle! [done]");
-
- bool ret = true;
- ret &= pipeline->SetProperty(Elements::kSinkAudio, "audio-swap", TRUE);
- ret &= pipeline->DirectPadFlushStartDownStream(Elements::kSinkAudio);
- ret &= pipeline->DirectPadFlushStopDownStream(Elements::kSinkAudio, false);
- ret &= pipeline->DirectSendSegmentEvent(
- Elements::kSinkAudio, rendering_start_time_, playback_rate_);
-
- TRACKRENDERER_LEAVE
- return ret;
- }
-
- private:
- static GstPadProbeReturn GstSrcPadProbeIdleAndBlockCb_(GstPad* pad,
- GstPadProbeInfo* info,
- gpointer userdata) {
- if (info->type & GST_PAD_PROBE_TYPE_BLOCK) {
- TRACKRENDERER_INFO("Pad Blocked!");
- }
- if (info->type & GST_PAD_PROBE_TYPE_IDLE) {
- TRACKRENDERER_INFO("Pad Idle!");
- Pipeline<Elements>::Pad* padprobe =
- static_cast<Pipeline<Elements>::Pad*>(userdata);
- std::unique_lock<std::mutex> lk(padprobe->m);
- padprobe->is_idle = true;
- TRACKRENDERER_INFO("Pad Idle notify_all()!");
- padprobe->cv.notify_all();
- }
- return GST_PAD_PROBE_OK;
- }
-
- private:
- const std::string kPadBlockProbeId_ =
- "RESYNC_AUDIO_SINK_PAD_IDLE_AND_BLOCK_PROBE";
- const GstPadProbeType kPadProbeType_ = static_cast<GstPadProbeType>(
- GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE);
-
- const std::uint64_t& rendering_start_time_;
- const double& playback_rate_;
-};
-} // namespace resync_audio
-} // namespace trackrenderer
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_SWDECODER_POLICY_HPP__
-// LCOV_EXCL_STOP
+++ /dev/null
-//
-// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_RESYNC_AUDIO_POLICY_H__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_RESYNC_AUDIO_POLICY_H__
-
-#include <memory>
-
-#include "trackrenderer/core/elements.h"
-#include "trackrenderer/core/pipeline.hpp"
-
-namespace plusplayer {
-namespace trackrenderer {
-struct ResyncAudioPolicy {
- using PipelinePtr = std::unique_ptr<Pipeline<Elements>>;
- virtual ~ResyncAudioPolicy() = default;
- virtual bool Resync(PipelinePtr& pipeline) = 0;
-};
-
-using ResyncAudioPolicyPtr = std::unique_ptr<ResyncAudioPolicy>;
-} // namespace trackrenderer
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_RESYNC_AUDIO_POLICY_H__
\ No newline at end of file
+++ /dev/null
-//
-// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_AUDIOEASINGINFO_H__
-#define __PLUSPLAYER_TRACKRENDERER_CORE_AUDIOEASINGINFO_H__
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-enum class AudioEasingType {
- kAudioEasingLinear = 0,
- kAudioEasingIncubic,
- kAudioEasingOutcubic,
- kAudioEasingNone
-};
-
-/**
- * @brief audio easing information struct
- */
-struct AudioEasingInfo {
- uint32_t target_volume; /**< Audio easing target volume */
- uint32_t duration; /**< Audio easing duration, in millisecond */
- AudioEasingType type; /**< Audio easing type */
-};
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_TRACKRENDERER_CORE_AUDIOEASINGINFO_H__
namespace trackrenderer {
/**
- * @brief Enumerations for the buffer status
- */
+* @brief Enumerations for the buffer status
+*/
enum class BufferStatus {
kUnderrun, // buffer underrun
kOverrun // buffer everrun
};
-enum class DecodedVideoFrameBufferType { kNone, kCopy, kReference, kRaw, kScale };
+enum class DecodedVideoFrameBufferType { kNone, kCopy, kReference };
struct DecodedVideoPacket {
uint64_t pts = 0;
uint64_t duration = 0;
- void* surface_data = nullptr; // tbm_surface
- void* scaler_index = nullptr;
-};
-
-enum class DecodedVideoRawModePacketType { kPhysicalAddress, kTizenBuffer };
-
-struct DecodedVideoRawModePacket {
- DecodedVideoRawModePacketType type =
- DecodedVideoRawModePacketType::kPhysicalAddress;
- uint64_t pts = 0;
- uint32_t width = 0;
- uint32_t height = 0;
- union {
- struct {
- int y_phyaddr = 0;
- int y_viraddr = 0;
- int y_linesize = 0;
- int uv_phyaddr = 0;
- int uv_viraddr = 0;
- int uv_linesize = 0;
- } raw;
- struct {
- tbm_key key;
- } tbm;
- } data = {.tbm = {0}};
+ tbm_surface_h surface_data = nullptr; // tbm_surface
+ void *scaler_index = nullptr;
};
static constexpr int kHandoffFrameBufferNum = 2;
bool TbmBufferAllocate(int width, int height) {
for (int i = 0; i < kHandoffFrameBufferNum; i++) {
- tbm_surface[i] = tbm_surface_create(width, height, TBM_FORMAT_NV12);
+ tbm_surface[i] =
+ tbm_surface_create(width, height, TBM_FORMAT_NV12);
if (!tbm_surface[i]) {
return false;
}
#include <queue>
#include "gst/gst.h"
-#include <drmdecrypt/drmdecrypt_api.h>
-
#include "trackrenderer/core/track.h"
namespace plusplayer {
static Ptr Create(const TrackType type = kTrackTypeMax,
const int index = kInvalidTrackIndex,
- GstBuffer* buffer = nullptr, bool incref = true) {
- return Ptr(new DecoderInputBuffer(buffer, type, index, incref));
+ GstBuffer* buffer = nullptr,
+ GstCaps * caps = nullptr,
+ bool incref = true) {
+ return Ptr(new DecoderInputBuffer(buffer, caps, type, index, incref));
}
DecoderInputBuffer() = delete;
while (std::atomic_flag_test_and_set_explicit(&buffer_lock_,
std::memory_order_acquire))
; // spin until the lock is acquired
- if (buffer_ && incref_) {
- ReleaseTZHandle_(buffer_);
- gst_buffer_unref(buffer_);
+ if (incref_) {
+ if (buffer_) {
+ gst_buffer_unref(buffer_);
+ }
+
+ if (caps_)
+ gst_caps_unref(caps_);
}
std::atomic_flag_clear_explicit(&buffer_lock_, std::memory_order_release);
}
const bool IsEos() const { return is_eos_; }
+ const GstCaps* GetCaps() const { return caps_; }
+
GstBuffer* Release() {
while (std::atomic_flag_test_and_set_explicit(&buffer_lock_,
std::memory_order_acquire))
const GstBuffer* Get() const { return buffer_; }
private:
- explicit DecoderInputBuffer(GstBuffer* buffer, const TrackType type,
- const int index, bool incref)
+ explicit DecoderInputBuffer(GstBuffer* buffer, GstCaps *caps,
+ const TrackType type, const int index, bool incref)
: type_(type), index_(index), incref_(incref) {
if (buffer) {
buffer_ = incref_ ? gst_buffer_ref(buffer) : buffer;
duration_ = GST_TIME_AS_MSECONDS(GST_BUFFER_DURATION(buffer_));
+ if (caps)
+ caps_ = incref_ ? gst_caps_ref(caps) : caps;
if (type == kTrackTypeSubtitle) {
GstMapInfo info;
gst_buffer_map(buffer_, &info, GST_MAP_READ);
}
}
- void ReleaseTZHandle_(GstBuffer* buffer) {
- GstStructure* tzqdata = GST_STRUCTURE(gst_mini_object_get_qdata(
- GST_MINI_OBJECT(buffer),
- g_quark_from_static_string("GstTzHandleData")));
-
- if (tzqdata) {
- gboolean ret = FALSE;
- guint packet_handle = 0;
- guint packet_size = 0;
- handle_and_size_s ret_Handle;
- memset(&ret_Handle, 0, sizeof(ret_Handle));
-
- ret = gst_structure_get_uint(tzqdata, "packet_handle", &packet_handle);
- if (FALSE == ret) {
- return;
- }
-
- ret = gst_structure_get_uint(tzqdata, "packet_size", &packet_size);
- if (FALSE == ret) {
- return;
- }
-
- ret_Handle.handle = packet_handle;
- ret_Handle.size = packet_size;
- release_handle(&ret_Handle);
- }
- }
-
private:
std::atomic_flag buffer_lock_ = ATOMIC_FLAG_INIT;
const TrackType type_ = kTrackTypeMax;
GstBuffer* buffer_ = nullptr;
uint32_t buffer_size_ = 0;
uint64_t duration_ = 0;
+ GstCaps * caps_ = nullptr;
const uint8_t* raw_data_ = nullptr;
};
double scale_h = 1.0;
};
-struct RenderRect {
- int x = 0, y = 0;
- int w = 1920, h = 1080;
-};
-
-struct ParDarInfo {
- uint64_t time_millisecond = 0;
- uint32_t par_num = 0;
- uint32_t par_den = 1;
- uint32_t dar_num = 0;
- uint32_t dar_den = 1;
-};
-
enum class StillMode { kNone, kOff, kOn };
} // namespace trackrenderer
kSecuremedia,
kSdrm,
kWidevineCdm = 8,
+ kClearkey,
kMax
};
LicenseAcquiredCb license_acquired_cb = nullptr; // The cb will be invoked when license was acquired.
UserData license_acquired_userdata = nullptr; // The userdata will be sent by license_acquired_cb
};
-
+
} // namespace drm
} // namespace trackrenderer
+++ /dev/null
-//\r
-// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
-//\r
-\r
-#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_ELEMENTS_H__\r
-#define __PLUSPLAYER_TRACKRENDERER_CORE_ELEMENTS_H__\r
-\r
-namespace plusplayer {\r
-\r
-namespace trackrenderer {\r
-\r
-enum class Elements {\r
- kPipeline, // must be the first\r
- kAppSrcVideo,\r
- kAppSrcAudio,\r
- kAppSrcSubtitle,\r
- kDrmVideo,\r
- kDrmAudio,\r
- kDecVideo,\r
- kDecAudio,\r
- kSinkVideo,\r
- kAudioConvert,\r
- kCapsFillterDefault,\r
- kCapsFillter2,\r
- kAudioResample,\r
- kScaleTempo,\r
- kSinkAudio,\r
- kSinkSubtitle,\r
- kBinVideo,\r
- kBinAudio,\r
- kBinSubtitle,\r
- kSinkCaption,\r
- kQueueCaption,\r
- kAiFilter,\r
- kMaxElements // must be the last\r
-};\r
-\r
-} // namespace trackrenderer\r
-\r
-} // namespace plusplayer\r
-\r
-#endif // __PLUSPLAYER_TRACKRENDERER_CORE_ELEMENTS_H__
\ No newline at end of file
kNotSupportedAudioCodec = TRACKRENDERER_ERROR_CLASS | 0x0e, /**< Not supported audio codec but video can be played (Since 4.0) */
kNotSupportedVideoCodec = TRACKRENDERER_ERROR_CLASS | 0x0f, /**< Not supported video codec but audio can be played (Since 4.0) */
kNotSupportedSubtitle = TRACKRENDERER_ERROR_CLASS | 0x10, /**< Not supported subtitle format (Since 4.0) */
-
+
kDrmInfo = TRACKRENDERER_CUSTOM_ERROR_CLASS | 0x05, /**< playready drm error info */
kNotSupportedFormat = TRACKRENDERER_CUSTOM_ERROR_CLASS | 0x08,
kStreamingPlayer = TRACKRENDERER_CUSTOM_ERROR_CLASS | 0x09,
-/**
- * @file
- * @brief The event for playback.
- * @interfacetype Module
- * @privlevel None-privilege
- * @privilege None
- * @product TV, AV, B2B
- * @version 1.0
- * @SDK_Support N
- * @remark This is a group of C style event related enum and structure.
- * @see N/A
- *
- * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
- * PROPRIETARY/CONFIDENTIAL
- * This software is the confidential and proprietary
- * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
- * not disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into with
- * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
- * suitability of the software, either express or implied, including but not
- * limited to the implied warranties of merchantability, fitness for a
- * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
- * damages suffered by licensee as a result of using, modifying or distributing
- * this software or its derivatives.
- */
-
-#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_EVENT_H__
-#define __PLUSPLAYER_TRACKRENDERER_CORE_EVENT_H__
-
-namespace plusplayer {
-
-namespace trackrenderer {
-/**
- * @brief
- */
-typedef struct {
- /**
- * @description
- */
- std::string data;
- /**
- * @description
- */
- uint64_t len;
-} EventMsg;
-
-/**
- * @brief
- */
-enum class EventType {
- kNone,
- kResolutionChanged,
-};
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_TRACKRENDERER_CORE_EVENT_H__
+/**\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_TRACKRENDERER_CORE_EVENT_H__\r
+#define __PLUSPLAYER_TRACKRENDERER_CORE_EVENT_H__\r
+\r
+namespace plusplayer {\r
+\r
+namespace trackrenderer {\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 trackrenderer\r
+\r
+} // namespace plusplayer\r
+\r
+#endif // __PLUSPLAYER_TRACKRENDERER_CORE_EVENT_H__\r
void GstInit();
void GstInit(const Json::Value& root);
-void ShowStateChangedMsg(GstMessage* msg, void* id = nullptr);
-void SetGstStateToNull(GstElement* pipeline, void* id = nullptr);
+void ShowStateChangedMsg(GstMessage* msg);
+void SetGstStateToNull(GstElement* pipeline);
const gchar* GetElementName(const GstMessage* msg);
const gchar* GetKlass(const GstMessage* msg);
}
void PrintCapsString();
- private:
+// private:
GstCaps* GetCaps_() const { return caps_; }
- private:
+// private:
GstCaps* caps_;
};
GstCapsBuilder(GstCapsBuilder&&) = delete;
GstCapsWrapper Build(const Track& track, bool is_drm);
+ GstCapsWrapper BuildOrgMediaType(const Track& track, bool is_drm);
private:
Recipe::CapsFiller FindCapsFiller_(const Track&, const std::string&);
+++ /dev/null
-//
-// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_LATENCY_H__
-#define __PLUSPLAYER_TRACKRENDERER_CORE_LATENCY_H__
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-enum class CatchUpSpeed {
- kNone,
- kSlow,
- kMid,
- kFast
-};
-
-enum class LatencyStatus {
- kLow,
- kMid,
- kHigh
-};
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_TRACKRENDERER_CORE_LATENCY_H__
\ No newline at end of file
+++ /dev/null
-//
-// @ Copyright [2021] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_PICTUREQUALITY_H__
-#define __PLUSPLAYER_TRACKRENDERER_CORE_PICTUREQUALITY_H__
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-/**
-* @brief Advanced Picture Quality Type.
-*/
-enum class AdvPictureQualityType {
- kVideoCall,
- kUsbCamera
-};
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_TRACKRENDERER_CORE_PICTUREQUALITY_H__
\ No newline at end of file
-//\r
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>\r
-//\r
-// Gstreamer facade\r
-//\r
-\r
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_PIPELINE_H__\r
-#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_PIPELINE_H__\r
-\r
-#include <malloc.h>\r
-\r
-#include <boost/core/noncopyable.hpp>\r
-#include <cassert>\r
-#include <condition_variable>\r
-#include <functional>\r
-#include <map>\r
-#include <memory>\r
-#include <mutex>\r
-#include <unordered_map>\r
-\r
-#include "glib-object.h"\r
-#include "gst/app/gstappsrc.h"\r
-#include "gst/gst.h"\r
-#include "trackrenderer/core/gst_utils.h"\r
-#include "trackrenderer/core/gstcaps_builder.h"\r
-#include "trackrenderer/core/gstobject_guard.h"\r
-#include "trackrenderer/core/gstsignal_holder.h"\r
-#include "trackrenderer/core/utils/log.h"\r
-\r
-namespace plusplayer {\r
-\r
-namespace trackrenderer {\r
-\r
-namespace trustzone {\r
-\r
-bool InitTzAppsrc();\r
-bool GstAppsrcPushBuffer(GstElement* appsrc, GstBuffer* buffer);\r
-\r
-} // namespace trustzone\r
-\r
-namespace pipeline_internal {\r
-\r
-inline GstElement* GetLastObj(GstElement* bin) {\r
- GValue data;\r
- memset(&data, 0, sizeof(data));\r
- auto data_guard = gstguard::make_guard(&data);\r
- GstIterator* it = gst_bin_iterate_elements(GST_BIN_CAST(bin));\r
- auto it_guard = gstguard::make_guard(it);\r
- GstIteratorResult ret = gst_iterator_next(it, &data);\r
- if (ret != GST_ITERATOR_OK) {\r
- return nullptr;\r
- }\r
- return static_cast<GstElement*>(g_value_get_object(&data));\r
-}\r
-\r
-} // namespace pipeline_internal\r
-\r
-template <typename T>\r
-class Pipeline : private boost::noncopyable {\r
- public:\r
- using Operator = std::function<bool(GstElement* element)>;\r
- struct Pad {\r
- std::mutex m;\r
- std::condition_variable cv;\r
- gulong probe_id = 0;\r
- bool is_idle = false;\r
- };\r
-\r
- public:\r
- using Ptr = std::unique_ptr<Pipeline<T>>;\r
- static Ptr Create(const char* name) {\r
- return Ptr(new Pipeline<T>(gst_pipeline_new(name)));\r
- }\r
-\r
- ~Pipeline() noexcept {\r
- std::lock_guard<std::mutex> lock(execute_mutex_);\r
- signals_.reset();\r
- TRACKRENDERER_DEBUG("[%p]", mainbin_[static_cast<int>(T::kPipeline)]);\r
- gst_object_unref(mainbin_[static_cast<int>(T::kPipeline)]);\r
- malloc_trim(0);\r
- for (int element_idx = static_cast<int>(T::kPipeline);\r
- element_idx < static_cast<int>(T::kMaxElements); element_idx++)\r
- mainbin_[element_idx] = nullptr;\r
- }\r
-\r
- // Purose of Execute\r
- // - serialization of gstreamer commands\r
- bool Execute(T type, Operator op) {\r
- std::lock_guard<std::mutex> lock(execute_mutex_);\r
- if (!mainbin_[static_cast<int>(type)]) return false;\r
- return op(mainbin_[static_cast<int>(type)]);\r
- }\r
-\r
- //////////////// /////////////////\r
- //////////////// Utilities (Entering) /////////////////\r
- //////////////// /////////////////\r
- bool FactoryMake(const T element, const char* name, const char* nickname) {\r
- if (!name) {\r
- TRACKRENDERER_ERROR("invalid element_name[null]");\r
- return false;\r
- }\r
- GstElement* obj = gst_element_factory_make(name, nickname);\r
-\r
- if (strstr(name, "tzappsrc")) {\r
- is_trustzone_element_[static_cast<int>(element)] = true;\r
- if (!InitTzAppsrc_()) return false;\r
- }\r
-\r
- if (!obj) {\r
- TRACKRENDERER_ERROR("Fail to create element[%s][%s]",\r
- name ? name : "(EMPTY)",\r
- nickname ? nickname : "(EMPTY)");\r
- return false;\r
- }\r
- return Set_(element, obj);\r
- }\r
-\r
- bool ElementAdd(const T element, void* obj) {\r
- if (!obj) {\r
- return false;\r
- }\r
- return Set_(element, static_cast<GstElement*>(gst_object_ref(obj)));\r
- }\r
-\r
- bool CreateBin(T element, const char* name) {\r
- GstElement* obj = gst_bin_new(name);\r
- return Set_(element, obj);\r
- }\r
-\r
- bool SignalConnect(T type, const char* name, GCallback handler,\r
- gpointer data) {\r
- std::lock_guard<std::mutex> lock(execute_mutex_);\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- signals_->Add(G_OBJECT(obj), name, handler, data);\r
- return true;\r
- }\r
-\r
- bool SetSyncHandler(GstBusSyncHandler func, gpointer user_data,\r
- GDestroyNotify notify) {\r
- GstElement* obj = mainbin_[static_cast<int>(T::kPipeline)];\r
- if (!obj) return false;\r
- auto bus =\r
- gstguard::make_guard<GstBus>(gst_pipeline_get_bus(GST_PIPELINE(obj)));\r
- if (bus) gst_bus_set_sync_handler(bus.get(), func, user_data, notify);\r
- return true;\r
- }\r
-\r
- template <typename... Args>\r
- bool SetProperty(T type, const char* name, Args... args) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- g_object_set(G_OBJECT(obj), name, args..., NULL);\r
- return true;\r
- }\r
-\r
- template <typename... Args>\r
- bool GetProperty(T type, const char* name, Args... args) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- g_object_get(G_OBJECT(obj), name, args..., NULL);\r
- return true;\r
- }\r
-\r
- //\r
- // BinRemove\r
- // description : remove each elements from bin\r
- //\r
- void BinRemove(T bin, T last) {\r
- GstElement* obj = mainbin_[static_cast<int>(last)];\r
- GstElement* bin_element = mainbin_[static_cast<int>(bin)];\r
- auto sink_pad =\r
- gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
- gst_pad_unlink(GST_PAD_PEER(sink_pad.get()), sink_pad.get());\r
-\r
- auto src_pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));\r
- if (src_pad) {\r
- // gst_pad_unlink(src_pad.get(), GST_PAD_PEER(src_pad.get()));\r
- assert(0 && "not support this feature");\r
- }\r
- gst_util::SetGstStateToNull(obj);\r
- gst_bin_remove_many(GST_BIN(bin_element), obj, nullptr);\r
- Unset_(last);\r
- }\r
-\r
- template <typename... Args>\r
- void BinRemove(T bin, T element, Args... args) {\r
- GstElement* obj = mainbin_[static_cast<int>(element)];\r
- GstElement* bin_element = mainbin_[static_cast<int>(bin)];\r
- if (obj) {\r
- auto sink_pad =\r
- gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
- gst_pad_unlink(GST_PAD_PEER(sink_pad.get()), sink_pad.get());\r
- gst_util::SetGstStateToNull(obj);\r
- gst_bin_remove_many(GST_BIN(bin_element), obj, nullptr);\r
- Unset_(element);\r
- }\r
- BinRemove(bin, args...);\r
- }\r
-\r
- //\r
- // BinAdd\r
- // description : add each elements to Bin , and link each elements\r
- //\r
- void BinAdd(T bin, T last) {\r
- GstElement* bin_obj = mainbin_[static_cast<int>(bin)];\r
- GstElement* obj = mainbin_[static_cast<int>(last)];\r
- assert(bin_obj && obj);\r
- GstElement* last_obj = pipeline_internal::GetLastObj(bin_obj);\r
- gst_bin_add(GST_BIN(bin_obj), obj);\r
- if (last_obj) {\r
- if (!gst_element_link(last_obj, obj)) {\r
- TRACKRENDERER_ERROR("elements link error");\r
- gst_bin_remove(GST_BIN(bin_obj), obj);\r
- return;\r
- }\r
- }\r
- if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(obj))) {\r
- TRACKRENDERER_ERROR("sync state with parent error");\r
- gst_bin_remove(GST_BIN(bin_obj), obj);\r
- return;\r
- }\r
- }\r
-\r
- template <typename... Args>\r
- void BinAdd(T bin, T element, Args... args) {\r
- GstElement* bin_obj = mainbin_[static_cast<int>(bin)];\r
- GstElement* obj = mainbin_[static_cast<int>(element)];\r
- assert(bin_obj);\r
- if (!obj) {\r
- BinAdd(bin, args...);\r
- return;\r
- }\r
- GstElement* last_obj = pipeline_internal::GetLastObj(bin_obj);\r
- gst_bin_add(GST_BIN(bin_obj), obj);\r
- if (last_obj) {\r
- // TRACKRENDERER_DEBUG("[%p] is linked to [%p]", obj, last_obj);\r
- if (!gst_element_link(last_obj, obj)) {\r
- TRACKRENDERER_ERROR("elements link error");\r
- gst_bin_remove(GST_BIN(bin_obj), obj);\r
- return;\r
- }\r
- }\r
- if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(obj))) {\r
- TRACKRENDERER_ERROR("sync state with parent error");\r
- gst_bin_remove(GST_BIN(bin_obj), obj);\r
- return;\r
- }\r
- BinAdd(bin, args...);\r
- }\r
-\r
- //\r
- // ElementLink\r
- // description : link elements\r
- //\r
- void ElementLink(T src, T dest) {\r
- GstElement* src_obj = mainbin_[static_cast<int>(src)];\r
- GstElement* dest_obj = mainbin_[static_cast<int>(dest)];\r
- assert(src_obj && dest_obj);\r
- if (!gst_element_link(src_obj, dest_obj)) {\r
- TRACKRENDERER_ERROR("elements link error");\r
- return;\r
- }\r
- if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(dest_obj))) {\r
- TRACKRENDERER_ERROR("sync state with parent error");\r
- gst_bin_remove(GST_BIN(gst_element_get_parent(dest_obj)), dest_obj);\r
- return;\r
- }\r
- }\r
-\r
- bool BinAddSimple(T dst, T src) {\r
- GstElement* bin = mainbin_[static_cast<int>(dst)];\r
- GstElement* obj = mainbin_[static_cast<int>(src)];\r
- if (!bin || !obj) {\r
- return false;\r
- }\r
- gst_bin_add(GST_BIN(bin), obj);\r
- if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(obj))) {\r
- TRACKRENDERER_ERROR("sync state with parent error");\r
- gst_bin_remove(GST_BIN(bin), obj);\r
- return false;\r
- }\r
- return true;\r
- }\r
- //\r
- // SetState\r
- //\r
- bool SetState(T element, GstState state) {\r
- GstElement* obj = mainbin_[static_cast<int>(element)];\r
- if (!obj) return false;\r
- if (state == GST_STATE_NULL) {\r
- gst_util::SetGstStateToNull(obj);\r
- return true;\r
- }\r
- GstStateChangeReturn ret = gst_element_set_state(obj, state);\r
- if (ret == GST_STATE_CHANGE_FAILURE) {\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- bool GetState(T element, GstState* cur_state, GstState* pending_state,\r
- GstClockTime timeout) {\r
- GstElement* obj = mainbin_[static_cast<int>(element)];\r
- if (!obj) return false;\r
- GstStateChangeReturn ret =\r
- gst_element_get_state(obj, cur_state, pending_state, timeout);\r
- if (ret == GST_STATE_CHANGE_FAILURE) {\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- bool GenerateDot(const gchar* file_name) {\r
- GstElement* pipeline = mainbin_[static_cast<int>(T::kPipeline)];\r
- if (!pipeline) return false;\r
- GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL,\r
- file_name);\r
- return true;\r
- }\r
-\r
- bool Seek(gdouble rate, GstFormat format, GstSeekFlags flags,\r
- GstSeekType start_type, gint64 start, GstSeekType stop_type,\r
- gint64 stop) {\r
- GstElement* obj = mainbin_[static_cast<int>(T::kPipeline)];\r
- if (!obj) return false;\r
- if (!gst_element_seek(obj, rate, format, flags, start_type, start,\r
- stop_type, stop)) {\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- bool AppSrcPushBuffer(T type, GstBuffer* buffer) {\r
- int index = static_cast<int>(type);\r
- GstElement* obj = mainbin_[index];\r
- if (!obj) return false;\r
- if (is_trustzone_element_[index]) {\r
- trustzone::GstAppsrcPushBuffer(obj, buffer);\r
- } else {\r
- gst_app_src_push_buffer(GST_APP_SRC(obj), buffer);\r
- }\r
-\r
- return true;\r
- }\r
-\r
- bool SetAppSrcCaps(T type, const GstCapsWrapper& caps) {\r
- return SetProperty(type, "caps", caps.GetCaps_());\r
- }\r
-\r
- bool SetPadCaps(T type, const char* mime_type) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));\r
- auto gstcaps = gstguard::make_guard(gst_caps_new_empty_simple(mime_type));\r
- if (!gst_pad_set_caps(pad.get(), gstcaps.get())) {\r
- TRACKRENDERER_ERROR("gst_pad_set_caps error");\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- template <typename... Args>\r
- bool SetPadCaps(T type, const char* mime_type, Args... caps) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));\r
- auto gstcaps =\r
- gstguard::make_guard(gst_caps_new_simple(mime_type, caps..., nullptr));\r
- if (!gst_pad_set_caps(pad.get(), gstcaps.get())) {\r
- TRACKRENDERER_ERROR("gst_pad_set_caps error");\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- GstCaps* GetSinkPadCaps(T type) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return nullptr;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
- auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad.get()));\r
- return gst_caps_copy(caps.get());\r
- }\r
-\r
- bool Flush(T type) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- bool ret = true;\r
- if (!gst_element_send_event(GST_ELEMENT_CAST(obj),\r
- gst_event_new_flush_start())) {\r
- TRACKRENDERER_ERROR("Fail to send flush start");\r
- ret = false;\r
- }\r
- if (!gst_element_send_event(GST_ELEMENT_CAST(obj),\r
- gst_event_new_flush_stop(FALSE))) {\r
- TRACKRENDERER_ERROR("Fail to send flush stop");\r
- ret = false;\r
- }\r
- return ret;\r
- }\r
-\r
- bool FlushDownStream(T type, gboolean reset_time) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));\r
- auto peer_pad = GST_PAD_PEER(pad.get());\r
- if (!gst_pad_send_event(peer_pad, gst_event_new_flush_start())) {\r
- TRACKRENDERER_ERROR("Fail to send flush start");\r
- return false;\r
- }\r
- if (!gst_pad_send_event(peer_pad, gst_event_new_flush_stop(reset_time))) {\r
- TRACKRENDERER_ERROR("Fail to send flush stop");\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- // LCOV_EXCL_START\r
- bool DirectPadFlushStartDownStream(T type) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
- if (!gst_pad_send_event(pad.get(), gst_event_new_flush_start())) {\r
- TRACKRENDERER_ERROR("Fail to send flush start");\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- bool DirectPadFlushStopDownStream(T type, bool reset_time) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
- if (!gst_pad_send_event(pad.get(), gst_event_new_flush_stop(reset_time))) {\r
- TRACKRENDERER_ERROR("Fail to send flush stop");\r
- return false;\r
- }\r
- return true;\r
- }\r
- // LCOV_EXCL_STOP\r
-\r
- bool PushSegmentEvent(T type, uint64_t position, gdouble rate) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));\r
- auto peer_pad = GST_PAD_PEER(pad.get());\r
- GstSegment segment;\r
- gst_segment_init(&segment, GST_FORMAT_TIME);\r
- segment.rate = rate;\r
- segment.start = position;\r
- segment.position = position;\r
- segment.time = position;\r
- GstEvent* seg_event = gst_event_new_segment(&segment);\r
- if (!gst_pad_send_event(peer_pad, seg_event)) {\r
- TRACKRENDERER_ERROR("Fail to send segment event");\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- // LCOV_EXCL_START\r
- bool DirectSendSegmentEvent(T type, uint64_t position, gdouble rate) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
- GstSegment segment;\r
- gst_segment_init(&segment, GST_FORMAT_TIME);\r
- segment.rate = rate;\r
- segment.start = position;\r
- segment.position = position;\r
- segment.time = position;\r
- if (!gst_pad_send_event(pad.get(), gst_event_new_segment(&segment))) {\r
- TRACKRENDERER_ERROR("Fail to send segment event");\r
- return false;\r
- }\r
- return true;\r
- }\r
- // LCOV_EXCL_STOP\r
-\r
- gulong GetPadProbeId(const char* key) {\r
- auto find = [](const PadProbeMap& map, const char* _key) -> bool {\r
- auto look = map.find(_key);\r
- if (look == map.end()) return false;\r
- return true;\r
- };\r
- if (!find(padprobe_id_, key)) return 0;\r
- return padprobe_id_[key].first;\r
- }\r
-\r
- bool PadAddProbe(T type, const char* key, const char* padname,\r
- GstPadProbeType mask, GstPadProbeCallback callback,\r
- gpointer user_data, GDestroyNotify destroy_data) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, padname));\r
- assert(pad);\r
- gulong id =\r
- gst_pad_add_probe(pad.get(), mask, callback, user_data, destroy_data);\r
- if (key) padprobe_id_[key] = {id, pad.get()};\r
- return true;\r
- }\r
-\r
- // LCOV_EXCL_START\r
- bool PeerPadAddProbe(T type, const char* key, const char* padname,\r
- GstPadProbeType mask, GstPadProbeCallback callback,\r
- gpointer user_data, GDestroyNotify destroy_data) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, padname));\r
- assert(pad);\r
- auto peerpad = gstguard::make_guard(gst_pad_get_peer(pad.get()));\r
- assert(peerpad);\r
- gulong id = gst_pad_add_probe(peerpad.get(), mask, callback, user_data,\r
- destroy_data);\r
- if (key) padprobe_id_[key] = {id, peerpad.get()};\r
- return true;\r
- }\r
- // LCOV_EXCL_STOP\r
-\r
- bool PadRemoveProbe(T type, const char* padname, const gulong id) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, padname));\r
- gst_pad_remove_probe(pad.get(), id);\r
- return true;\r
- }\r
-\r
- bool PadRemoveProbe(const char* key) {\r
- auto find = [](const PadProbeMap& map, const char* _key) -> bool {\r
- auto look = map.find(_key);\r
- if (look == map.end()) return false;\r
- return true;\r
- };\r
- if (!find(padprobe_id_, key)) return false;\r
- gst_pad_remove_probe(padprobe_id_[key].second, padprobe_id_[key].first);\r
- return true;\r
- }\r
-\r
- bool SignalEmitByName(T type, const char* name) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- GstFlowReturn ret;\r
- g_signal_emit_by_name(gpointer(obj), name, &ret);\r
- TRACKRENDERER_DEBUG("g emit signal [%s] ret[%d]", name, ret);\r
- return true;\r
- }\r
-\r
- bool QueryPosition(T type, GstFormat format, int64_t* position) {\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- return gst_element_query_position(obj, format, position);\r
- }\r
-\r
- bool QuerySegment(T type, GstSegment* segment) {\r
- if (segment == nullptr) return false;\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
-\r
- auto query = gstguard::make_guard(gst_query_new_segment(GST_FORMAT_TIME));\r
- if (gst_element_query(obj, query.get()) == false) {\r
- TRACKRENDERER_ERROR("Fail to query segment");\r
- return false;\r
- }\r
-\r
- gdouble rate;\r
- GstFormat format;\r
- gint64 starttime, stoptime;\r
- gst_query_parse_segment(query.get(), &rate, &format, &starttime, &stoptime);\r
- TRACKRENDERER_DEBUG(\r
- "Segment : format(%d), rate(parsed:%lf), starttime(%lld), "\r
- "stoptime(%lld)",\r
- format, rate, starttime, stoptime);\r
-\r
- gst_segment_init(segment, format);\r
- segment->rate = rate;\r
- segment->start = starttime;\r
- segment->stop = stoptime;\r
- return true;\r
- }\r
-\r
- void SetGstElementCreatedCbHandler(std::function<void(T)> handler) {\r
- on_gstelement_created_cb_handler_ = handler;\r
- }\r
-\r
- bool SetParDar(T type, uint64_t timestamp, uint32_t VParN, uint32_t VParD,\r
- uint32_t VDarN, uint32_t VDarD) {\r
- TRACKRENDERER_ERROR("SetParDar enter");\r
- GstElement* obj = mainbin_[static_cast<int>(type)];\r
- if (!obj) return false;\r
- auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
- bool ret = true;\r
- timestamp *= G_GINT64_CONSTANT(1000000); // ms->ns\r
- GstStructure* pardar_structure = gst_structure_new(\r
- "GstPARDAR_Changed", "pkt_timestamp", G_TYPE_UINT64, timestamp, "vParN",\r
- G_TYPE_UINT, VParN, "vParD", G_TYPE_UINT, VParD, "vDarN", G_TYPE_UINT,\r
- VDarN, "vDarD", G_TYPE_UINT, VDarD, NULL);\r
- GstEvent* pardar_event = gst_event_new_custom(\r
- GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, pardar_structure);\r
- if (!gst_pad_send_event(pad.get(), pardar_event)) {\r
- TRACKRENDERER_ERROR("Fail to send par and dar");\r
- ret = false;\r
- }\r
- TRACKRENDERER_ERROR("send par and dar to video decoder successfully");\r
- return ret;\r
- }\r
-\r
- //////////////// /////////////////\r
- //////////////// Utilities (Leaving) /////////////////\r
- //////////////// /////////////////\r
-\r
- private:\r
- explicit Pipeline(GstElement* pipeline) noexcept {\r
- assert(pipeline && "pipeline is null");\r
- mainbin_[static_cast<int>(T::kPipeline)] = pipeline;\r
- }\r
-\r
- bool Set_(T type, GstElement* element) {\r
- std::lock_guard<std::mutex> lock(execute_mutex_);\r
- assert(element && (type < T::kMaxElements));\r
- assert(mainbin_[static_cast<int>(type)] == nullptr);\r
- TRACKRENDERER_DEBUG("TYPE[%d] ELEMENT[%p]", static_cast<int>(type),\r
- element);\r
- mainbin_[static_cast<int>(type)] = element;\r
- if (on_gstelement_created_cb_handler_ != nullptr)\r
- on_gstelement_created_cb_handler_(type);\r
- return true;\r
- }\r
-\r
- bool Unset_(T type) {\r
- assert(type < T::kMaxElements);\r
- assert(mainbin_[static_cast<int>(type)] != nullptr);\r
- TRACKRENDERER_DEBUG("TYPE[%d]", static_cast<int>(type));\r
- mainbin_[static_cast<int>(type)] = nullptr;\r
- return true;\r
- }\r
-\r
- bool InitTzAppsrc_() { return trustzone::InitTzAppsrc(); }\r
-\r
- private:\r
- using PadProbeMap =\r
- std::unordered_map<std::string, std::pair<gulong, GstPad*>>;\r
-\r
- private:\r
- std::mutex execute_mutex_;\r
- GstElement* mainbin_[static_cast<int>(T::kMaxElements)]{\r
- nullptr,\r
- };\r
- std::unique_ptr<GstSignalHolder> signals_{new GstSignalHolder};\r
- PadProbeMap padprobe_id_;\r
- std::function<void(T)> on_gstelement_created_cb_handler_;\r
- bool is_trustzone_element_[static_cast<int>(T::kMaxElements)]{\r
- false,\r
- };\r
-}; // struct TrackRenderer::Pipeline\r
-\r
-} // namespace trackrenderer\r
-\r
-} // namespace plusplayer\r
-\r
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_PIPELINE_H__\r
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+// Gstreamer facade
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_PIPELINE_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_PIPELINE_H__
+
+#include <malloc.h>
+
+#include <boost/core/noncopyable.hpp>
+#include <cassert>
+#include <condition_variable>
+#include <functional>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+
+#include "glib-object.h"
+#include "gst/app/gstappsrc.h"
+#include "gst/gst.h"
+#include "trackrenderer/core/gst_utils.h"
+#include "trackrenderer/core/gstcaps_builder.h"
+#include "trackrenderer/core/gstobject_guard.h"
+#include "trackrenderer/core/gstsignal_holder.h"
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace trustzone {
+
+bool InitTzAppsrc();
+bool GstAppsrcPushBuffer(GstElement* appsrc, GstBuffer* buffer);
+
+} // namespace trustzone
+
+namespace pipeline_internal {
+
+inline GstElement* GetLastObj(GstElement* bin) {
+ GValue data;
+ memset(&data, 0, sizeof(data));
+ auto data_guard = gstguard::make_guard(&data);
+ GstIterator* it = gst_bin_iterate_elements(GST_BIN_CAST(bin));
+ auto it_guard = gstguard::make_guard(it);
+ GstIteratorResult ret = gst_iterator_next(it, &data);
+ if (ret != GST_ITERATOR_OK) {
+ return nullptr;
+ }
+ return static_cast<GstElement*>(g_value_get_object(&data));
+}
+
+} // namespace pipeline_internal
+
+template <typename T>
+class Pipeline : private boost::noncopyable {
+ public:
+ using Operator = std::function<bool(GstElement* element)>;
+ struct Pad {
+ std::mutex m;
+ std::condition_variable cv;
+ gulong probe_id = 0;
+ bool is_idle = false;
+ };
+
+ public:
+ using Ptr = std::unique_ptr<Pipeline<T>>;
+ static Ptr Create(const char* name) {
+ return Ptr(new Pipeline<T>(gst_pipeline_new(name)));
+ }
+
+ ~Pipeline() noexcept {
+ std::lock_guard<std::mutex> lock(execute_mutex_);
+ signals_.reset();
+ TRACKRENDERER_DEBUG("[%p]", mainbin_[static_cast<int>(T::kPipeline)]);
+ gst_object_unref(mainbin_[static_cast<int>(T::kPipeline)]);
+ malloc_trim(0);
+ for (int element_idx = static_cast<int>(T::kPipeline);
+ element_idx < static_cast<int>(T::kMaxElements); element_idx++)
+ mainbin_[element_idx] = nullptr;
+ }
+
+ // Purose of Execute
+ // - serialization of gstreamer commands
+ bool Execute(T type, Operator op) {
+ std::lock_guard<std::mutex> lock(execute_mutex_);
+ if (!mainbin_[static_cast<int>(type)]) return false;
+ return op(mainbin_[static_cast<int>(type)]);
+ }
+
+ //////////////// /////////////////
+ //////////////// Utilities (Entering) /////////////////
+ //////////////// /////////////////
+ bool FactoryMake(const T element, const char* name, const char* nickname) {
+ if (!name) {
+ TRACKRENDERER_ERROR("invalid element_name[null]");
+ return false;
+ }
+ GstElement* obj = gst_element_factory_make(name, nickname);
+
+ if (strstr(name, "tzappsrc")) {
+ is_trustzone_element_[static_cast<int>(element)] = true;
+ if (!InitTzAppsrc_()) return false;
+ }
+
+ if (!obj) {
+ TRACKRENDERER_ERROR("Fail to create element [%s]", name);
+ return false;
+ }
+ return Set_(element, obj);
+ }
+
+ bool FactoryMake(const T element, GstCaps *caps, GstElementFactoryListType type, const char* nickname) {
+ GList *factories = NULL;
+ GList *filtered = NULL;
+ GstElementFactory *factory = nullptr;
+ GstElement* obj = nullptr;
+
+ if (!caps) {
+ TRACKRENDERER_ERROR("invalid caps [null]");
+ return false;
+ }
+
+ auto caps_str = gstguard::make_guard(gst_caps_to_string(caps));
+ TRACKRENDERER_DEBUG("finding factory based on [%s]", caps_str.get());
+
+ /* get all compatible factories for caps */
+ factories =
+ gst_element_factory_list_get_elements (type, GST_RANK_MARGINAL);
+ if (factories) {
+ filtered =
+ gst_element_factory_list_filter (factories, caps, GST_PAD_SINK,
+ gst_caps_is_fixed (caps));
+ gst_plugin_feature_list_free(factories);
+ }
+
+ if (filtered) {
+ GList *l = filtered;
+ while(l) {
+ factory = GST_ELEMENT_FACTORY_CAST (l->data);
+ /* FIXME : need to skip avdec element for mp3 decoder */
+ if (!strstr(GST_OBJECT_NAME(factory), "avdec_mp1float") &&
+ !strstr(GST_OBJECT_NAME(factory), "avdec_mp2float") &&
+ !strstr(GST_OBJECT_NAME(factory), "avdec_mp3float")) {
+ break;
+ }
+ TRACKRENDERER_DEBUG("skip %s factory", GST_OBJECT_NAME(factory));
+ l = l->next;
+ }
+ TRACKRENDERER_DEBUG("factory name : %s", GST_OBJECT_NAME(factory));
+ obj = gst_element_factory_create(factory, nickname);
+ gst_plugin_feature_list_free (filtered);
+ }
+
+ if (!obj) {
+ TRACKRENDERER_ERROR("Fail to create element");
+ return false;
+ }
+ return Set_(element, obj);
+ }
+
+ bool CreateBin(T element, const char* name) {
+ GstElement* obj = gst_bin_new(name);
+ return Set_(element, obj);
+ }
+
+ bool SignalConnect(T type, const char* name, GCallback handler,
+ gpointer data) {
+ std::lock_guard<std::mutex> lock(execute_mutex_);
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ signals_->Add(G_OBJECT(obj), name, handler, data);
+ return true;
+ }
+
+ bool SetSyncHandler(GstBusSyncHandler func, gpointer user_data,
+ GDestroyNotify notify) {
+ GstElement* obj = mainbin_[static_cast<int>(T::kPipeline)];
+ if (!obj) return false;
+ auto bus =
+ gstguard::make_guard<GstBus>(gst_pipeline_get_bus(GST_PIPELINE(obj)));
+ if (bus) gst_bus_set_sync_handler(bus.get(), func, user_data, notify);
+ return true;
+ }
+
+ template <typename... Args>
+ bool SetProperty(T type, const char* name, Args... args) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ g_object_set(G_OBJECT(obj), name, args..., NULL);
+ return true;
+ }
+
+ template <typename... Args>
+ bool GetProperty(T type, const char* name, Args... args) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ g_object_get(G_OBJECT(obj), name, args..., NULL);
+ return true;
+ }
+
+ //
+ // BinRemove
+ // description : remove each elements from bin
+ //
+ void BinRemove(T bin, T last) {
+ GstElement* obj = mainbin_[static_cast<int>(last)];
+ GstElement* bin_element = mainbin_[static_cast<int>(bin)];
+ auto sink_pad =
+ gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));
+ gst_pad_unlink(GST_PAD_PEER(sink_pad.get()), sink_pad.get());
+
+ auto src_pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));
+ if (src_pad) {
+ // gst_pad_unlink(src_pad.get(), GST_PAD_PEER(src_pad.get()));
+ assert(0 && "not support this feature");
+ }
+ gst_util::SetGstStateToNull(obj);
+ gst_bin_remove_many(GST_BIN(bin_element), obj, nullptr);
+ Unset_(last);
+ }
+
+ template <typename... Args>
+ void BinRemove(T bin, T element, Args... args) {
+ GstElement* obj = mainbin_[static_cast<int>(element)];
+ GstElement* bin_element = mainbin_[static_cast<int>(bin)];
+ if (obj) {
+ auto sink_pad =
+ gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));
+ gst_pad_unlink(GST_PAD_PEER(sink_pad.get()), sink_pad.get());
+ gst_util::SetGstStateToNull(obj);
+ gst_bin_remove_many(GST_BIN(bin_element), obj, nullptr);
+ Unset_(element);
+ }
+ BinRemove(bin, args...);
+ }
+
+ //
+ // BinAdd
+ // description : add each elements to Bin , and link each elements
+ //
+ void BinAdd(T bin, T last) {
+ GstElement* bin_obj = mainbin_[static_cast<int>(bin)];
+ GstElement* obj = mainbin_[static_cast<int>(last)];
+ assert(bin_obj && obj);
+ GstElement* last_obj = pipeline_internal::GetLastObj(bin_obj);
+ gst_bin_add(GST_BIN(bin_obj), obj);
+ if (last_obj) {
+ if (!gst_element_link(last_obj, obj)) {
+ TRACKRENDERER_ERROR("elements link error");
+ gst_bin_remove(GST_BIN(bin_obj), obj);
+ return;
+ }
+ }
+ if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(obj))) {
+ TRACKRENDERER_ERROR("sync state with parent error");
+ gst_bin_remove(GST_BIN(bin_obj), obj);
+ return;
+ }
+ }
+
+ template <typename... Args>
+ void BinAdd(T bin, T element, Args... args) {
+ GstElement* bin_obj = mainbin_[static_cast<int>(bin)];
+ GstElement* obj = mainbin_[static_cast<int>(element)];
+ assert(bin_obj);
+ if (!obj) {
+ BinAdd(bin, args...);
+ return;
+ }
+ GstElement* last_obj = pipeline_internal::GetLastObj(bin_obj);
+ gst_bin_add(GST_BIN(bin_obj), obj);
+ if (last_obj) {
+ // TRACKRENDERER_DEBUG("[%p] is linked to [%p]", obj, last_obj);
+ if (!gst_element_link(last_obj, obj)) {
+ TRACKRENDERER_ERROR("elements link error");
+ gst_bin_remove(GST_BIN(bin_obj), obj);
+ return;
+ }
+ }
+ if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(obj))) {
+ TRACKRENDERER_ERROR("sync state with parent error");
+ gst_bin_remove(GST_BIN(bin_obj), obj);
+ return;
+ }
+ BinAdd(bin, args...);
+ }
+
+ //
+ // ElementLink
+ // description : link elements
+ //
+ void ElementLink(T src, T dest) {
+ GstElement* src_obj = mainbin_[static_cast<int>(src)];
+ GstElement* dest_obj = mainbin_[static_cast<int>(dest)];
+ assert(src_obj && dest_obj);
+ if (!gst_element_link(src_obj, dest_obj)) {
+ TRACKRENDERER_ERROR("elements link error");
+ return;
+ }
+ if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(dest_obj))) {
+ TRACKRENDERER_ERROR("sync state with parent error");
+ gst_bin_remove(GST_BIN(gst_element_get_parent(dest_obj)), dest_obj);
+ return;
+ }
+ }
+
+ bool BinAddSimple(T dst, T src) {
+ GstElement* bin = mainbin_[static_cast<int>(dst)];
+ GstElement* obj = mainbin_[static_cast<int>(src)];
+ if (!bin || !obj) {
+ return false;
+ }
+ gst_bin_add(GST_BIN(bin), obj);
+ if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(obj))) {
+ TRACKRENDERER_ERROR("sync state with parent error");
+ gst_bin_remove(GST_BIN(bin), obj);
+ return false;
+ }
+ return true;
+ }
+ //
+ // SetState
+ //
+ bool SetState(T element, GstState state) {
+ GstElement* obj = mainbin_[static_cast<int>(element)];
+ if (!obj) return false;
+ if (state == GST_STATE_NULL) {
+ gst_util::SetGstStateToNull(obj);
+ return true;
+ }
+ GstStateChangeReturn ret = gst_element_set_state(obj, state);
+ if (ret == GST_STATE_CHANGE_FAILURE) {
+ return false;
+ }
+ return true;
+ }
+
+ bool GetState(T element, GstState* cur_state, GstState* pending_state,
+ GstClockTime timeout) {
+ GstElement* obj = mainbin_[static_cast<int>(element)];
+ if (!obj) return false;
+ GstStateChangeReturn ret =
+ gst_element_get_state(obj, cur_state, pending_state, timeout);
+ if (ret == GST_STATE_CHANGE_FAILURE) {
+ return false;
+ }
+ return true;
+ }
+
+ bool GenerateDot(const gchar* file_name) {
+ GstElement* pipeline = mainbin_[static_cast<int>(T::kPipeline)];
+ if (!pipeline) return false;
+ GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL,
+ file_name);
+ return true;
+ }
+
+ bool Seek(gdouble rate, GstFormat format, GstSeekFlags flags,
+ GstSeekType start_type, gint64 start, GstSeekType stop_type,
+ gint64 stop) {
+ GstElement* obj = mainbin_[static_cast<int>(T::kPipeline)];
+ if (!obj) return false;
+ if (!gst_element_seek(obj, rate, format, flags, start_type, start,
+ stop_type, stop)) {
+ return false;
+ }
+ return true;
+ }
+
+ bool AppSrcPushBuffer(T type, GstBuffer* buffer) {
+ int index = static_cast<int>(type);
+ GstElement* obj = mainbin_[index];
+ if (!obj) return false;
+ if (is_trustzone_element_[index]) {
+ trustzone::GstAppsrcPushBuffer(obj, buffer);
+ } else {
+ gst_app_src_push_buffer(GST_APP_SRC(obj), buffer);
+ }
+
+ return true;
+ }
+
+ bool SetAppSrcCaps(T type, const GstCapsWrapper& caps) {
+ return SetProperty(type, "caps", caps.GetCaps_());
+ }
+
+
+ bool SetAppSrcCaps(T type, const GstCaps * caps) {
+ return SetProperty(type, "caps", caps);
+ }
+
+ bool SetPadCaps(T type, const char* mime_type) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));
+ auto gstcaps = gstguard::make_guard(gst_caps_new_empty_simple(mime_type));
+ if (!gst_pad_set_caps(pad.get(), gstcaps.get())) {
+ TRACKRENDERER_ERROR("gst_pad_set_caps error");
+ return false;
+ }
+ return true;
+ }
+
+ template <typename... Args>
+ bool SetPadCaps(T type, const char* mime_type, Args... caps) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));
+ auto gstcaps =
+ gstguard::make_guard(gst_caps_new_simple(mime_type, caps..., nullptr));
+ if (!gst_pad_set_caps(pad.get(), gstcaps.get())) {
+ TRACKRENDERER_ERROR("gst_pad_set_caps error");
+ return false;
+ }
+ return true;
+ }
+
+ GstCaps* GetSrcPadCaps(T type) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return nullptr;
+ auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));
+ auto caps = gst_pad_has_current_caps(pad.get()) == TRUE
+ ? gstguard::make_guard(gst_pad_get_current_caps(pad.get()))
+ : gstguard::make_guard(gst_pad_query_caps(pad.get(), NULL));
+ return gst_caps_copy(caps.get());
+ }
+
+ GstCaps* GetSinkPadCaps(T type) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return nullptr;
+ auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));
+ auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad.get()));
+ return gst_caps_copy(caps.get());
+ }
+
+ bool Flush(T type) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ if (!gst_element_send_event(GST_ELEMENT_CAST(obj),
+ gst_event_new_flush_start())) {
+ TRACKRENDERER_ERROR("Fail to send flush start");
+ return false;
+ }
+ if (!gst_element_send_event(GST_ELEMENT_CAST(obj),
+ gst_event_new_flush_stop(FALSE))) {
+ TRACKRENDERER_ERROR("Fail to send flush stop");
+ return false;
+ }
+ return true;
+ }
+
+ bool FlushDownStream(T type) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));
+ auto peer_pad = GST_PAD_PEER(pad.get());
+ if (!gst_pad_send_event(peer_pad, gst_event_new_flush_start())) {
+ TRACKRENDERER_ERROR("Fail to send flush start");
+ return false;
+ }
+ if (!gst_pad_send_event(peer_pad, gst_event_new_flush_stop(FALSE))) {
+ TRACKRENDERER_ERROR("Fail to send flush stop");
+ return false;
+ }
+ return true;
+ }
+
+ gulong GetPadProbeId(const char* key) {
+ auto find = [](const PadProbeMap& map, const char* _key) -> bool {
+ auto look = map.find(_key);
+ if (look == map.end()) return false;
+ return true;
+ };
+ if (!find(padprobe_id_, key)) return 0;
+ return padprobe_id_[key].first;
+ }
+
+ bool PadAddProbe(T type, const char* key, const char* padname,
+ GstPadProbeType mask, GstPadProbeCallback callback,
+ gpointer user_data, GDestroyNotify destroy_data) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, padname));
+ assert(pad);
+ gulong id =
+ gst_pad_add_probe(pad.get(), mask, callback, user_data, destroy_data);
+ if (key) padprobe_id_[key] = {id, pad.get()};
+ return true;
+ }
+
+ bool PadRemoveProbe(T type, const char* padname, const gulong id) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, padname));
+ gst_pad_remove_probe(pad.get(), id);
+ return true;
+ }
+
+ bool PadRemoveProbe(const char* key) {
+ auto find = [](const PadProbeMap& map, const char* _key) -> bool {
+ auto look = map.find(_key);
+ if (look == map.end()) return false;
+ return true;
+ };
+ if (!find(padprobe_id_, key)) return false;
+ gst_pad_remove_probe(padprobe_id_[key].second, padprobe_id_[key].first);
+ return true;
+ }
+
+ bool SignalEmitByName(T type, const char* name) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ GstFlowReturn ret;
+ g_signal_emit_by_name(gpointer(obj), name, &ret);
+ TRACKRENDERER_DEBUG("g emit signal [%s] ret[%d]", name, ret);
+ return true;
+ }
+
+ bool QueryPosition(T type, GstFormat format, int64_t* position) {
+ GstElement* obj = mainbin_[static_cast<int>(type)];
+ if (!obj) return false;
+ return gst_element_query_position(obj, format, position);
+ }
+
+ void SetGstElementCreatedCbHandler(std::function<void(T)> handler) {
+ on_gstelement_created_cb_handler_ = handler;
+ }
+
+ bool IsFactoryListType(T element, GstElementFactoryListType type) {
+ GstElement* obj = mainbin_[static_cast<int>(element)];
+ if (!obj) return false;
+ return gst_element_factory_list_is_type(gst_element_get_factory(obj), type);
+ }
+
+ //////////////// /////////////////
+ //////////////// Utilities (Leaving) /////////////////
+ //////////////// /////////////////
+
+ private:
+ explicit Pipeline(GstElement* pipeline) noexcept {
+ assert(pipeline && "pipeline is null");
+ mainbin_[static_cast<int>(T::kPipeline)] = pipeline;
+ }
+
+ bool Set_(T type, GstElement* element) {
+ std::lock_guard<std::mutex> lock(execute_mutex_);
+ assert(element && (type < T::kMaxElements));
+ assert(mainbin_[static_cast<int>(type)] == nullptr);
+ TRACKRENDERER_DEBUG("TYPE[%d] ELEMENT[%p]", static_cast<int>(type),
+ element);
+ mainbin_[static_cast<int>(type)] = element;
+ if (on_gstelement_created_cb_handler_ != nullptr)
+ on_gstelement_created_cb_handler_(type);
+ return true;
+ }
+
+ bool Unset_(T type) {
+ assert(type < T::kMaxElements);
+ assert(mainbin_[static_cast<int>(type)] != nullptr);
+ TRACKRENDERER_DEBUG("TYPE[%d]", static_cast<int>(type));
+ mainbin_[static_cast<int>(type)] = nullptr;
+ return true;
+ }
+
+ bool InitTzAppsrc_() { return trustzone::InitTzAppsrc(); }
+
+ private:
+ using PadProbeMap =
+ std::unordered_map<std::string, std::pair<gulong, GstPad*>>;
+
+ private:
+ std::mutex execute_mutex_;
+ GstElement* mainbin_[static_cast<int>(T::kMaxElements)]{
+ nullptr,
+ };
+ std::unique_ptr<GstSignalHolder> signals_{new GstSignalHolder};
+ PadProbeMap padprobe_id_;
+ std::function<void(T)> on_gstelement_created_cb_handler_;
+ bool is_trustzone_element_[static_cast<int>(T::kMaxElements)]{
+ false,
+ };
+}; // struct TrackRenderer::Pipeline
+
+} // namespace trackrenderer
+
+} // namespace plusplayer
+
+#endif // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_PIPELINE_H__
+++ /dev/null
-//
-// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_SCREENSAVER_H__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_SCREENSAVER_H__
-
-#include <boost/core/noncopyable.hpp>
-
-#include "glib.h"
-#include "screensaver.h"
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-class ScreenSaver : private boost::noncopyable {
- public:
- ~ScreenSaver();
- static void StartTimeout();
- static void StopTimeout();
-
- private:
- static gboolean ResetTimeout(gpointer data);
-
- private:
-};
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_SCREENSAVER_H__
\ No newline at end of file
+++ /dev/null
-//
-// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_SUBTITLE_ATTR_H__
-#define __PLUSPLAYER_TRACKRENDERER_CORE_SUBTITLE_ATTR_H__
-
-#include <boost/any.hpp>
-#include <cstdint>
-#include <limits>
-#include <list>
-#include <memory>
-
-namespace plusplayer {
-namespace trackrenderer {
-enum SubtitleAttrType {
- kSubAttrRegionXPos = 0, // float type
- kSubAttrRegionYPos, // float type
- kSubAttrRegionWidth, // float type
- kSubAttrRegionHeight, // float type
- kSubAttrWindowXPadding, // float type
- kSubAttrWindowYPadding, // float type
- kSubAttrWindowLeftMargin, // int type
- kSubAttrWindowRightMargin, // int type
- kSubAttrWindowTopMargin, // int type
- kSubAttrWindowBottomMargin, // int type
- kSubAttrWindowBgColor, // int type
- kSubAttrWindowOpacity, // float type
- kSubAttrWindowShowBg, // how to show window background, uint type
- kSubAttrFontFamily, // char* type
- kSubAttrFontSize, // float type
- kSubAttrFontWeight, // int type
- kSubAttrFontStyle, // int type
- kSubAttrFontColor, // int type
- kSubAttrFontBgColor, // int type
- kSubAttrFontOpacity, // float type
- kSubAttrFontBgOpacity, // float type
- kSubAttrFontTextOutlineColor, // int type
- kSubAttrFontTextOutlineThickness, // int type
- kSubAttrFontTextOutlineBlurRadius, // int type
- kSubAttrFontVerticalAlign, // int type
- kSubAttrFontHorizontalAlign, // int type
- kSubAttrRawSubtitle, // char* type
- kSubAttrWebvttCueLine, // float type
- kSubAttrWebvttCueLineNum, // int type
- kSubAttrWebvttCueLineAlign, // int type
- kSubAttrWebvttCueAlign, // int type
- kSubAttrWebvttCueSize, // float type
- kSubAttrWebvttCuePosition, // float type
- kSubAttrWebvttCuePositionAlign, // int type
- kSubAttrWebvttCueVertical, // int type
- kSubAttrTimestamp,
- kSubAttrExtsubIndex, // File index of external subtitle
- kSubAttrTypeNone
-};
-
-enum class SubtitleType { kText, kPicture, kInvalid };
-
-struct SubtitleAttr {
- explicit SubtitleAttr(const SubtitleAttrType _type,
- const uint32_t _start_time, const uint32_t _stop_time,
- const boost::any _value, const int _extsub_index)
- : type(_type),
- start_time(_start_time),
- stop_time(_stop_time),
- value(_value),
- extsub_index(_extsub_index) {}
- const SubtitleAttrType type = kSubAttrTypeNone;
- const uint32_t start_time = std::numeric_limits<uint32_t>::max();
- const uint32_t stop_time = std::numeric_limits<uint32_t>::max();
- const boost::any value;
- const int extsub_index = -1;
-};
-using SubtitleAttrList = std::list<SubtitleAttr>;
-using SubtitleAttrListPtr = std::unique_ptr<SubtitleAttrList>;
-} // namespace trackrenderer
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_TRACKRENDERER_CORE_SUBTITLE_ATTR_H__
\ No newline at end of file
#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_TRACK_H__
#define __PLUSPLAYER_TRACKRENDERER_CORE_TRACK_H__
+#include <boost/any.hpp>
+#include <boost/core/noncopyable.hpp>
+#include <cstdint>
+#include <limits>
+#include <list>
#include <memory>
#include <string>
bool use_swdecoder = false;
std::string language_code;
std::string subtitle_format;
- std::string layout;
- std::string codec_tag;
- int flavor = 0;
+ std::string stream_format;
+ std::string alignment;
+ std::string original_media_type;
+ std::string protection_system;
};
-struct Rational {
- int num = 0; // the numerator value
- int den = 0; // the denominator value
+enum SubtitleAttrType {
+ kSubAttrRegionXPos = 0, // float type
+ kSubAttrRegionYPos, // float type
+ kSubAttrRegionWidth, // float type
+ kSubAttrRegionHeight, // float type
+ kSubAttrWindowXPadding, // float type
+ kSubAttrWindowYPadding, // float type
+ kSubAttrWindowLeftMargin, // int type
+ kSubAttrWindowRightMargin, // int type
+ kSubAttrWindowTopMargin, // int type
+ kSubAttrWindowBottomMargin, // int type
+ kSubAttrWindowBgColor, // int type
+ kSubAttrWindowOpacity, // float type
+ kSubAttrWindowShowBg, // how to show window background, uint type
+ kSubAttrFontFamily, // char* type
+ kSubAttrFontSize, // float type
+ kSubAttrFontWeight, // int type
+ kSubAttrFontStyle, // int type
+ kSubAttrFontColor, // int type
+ kSubAttrFontBgColor, // int type
+ kSubAttrFontOpacity, // float type
+ kSubAttrFontBgOpacity, // float type
+ kSubAttrFontTextOutlineColor, // int type
+ kSubAttrFontTextOutlineThickness, // int type
+ kSubAttrFontTextOutlineBlurRadius, // int type
+ kSubAttrFontVerticalAlign, // int type
+ kSubAttrFontHorizontalAlign, // int type
+ kSubAttrRawSubtitle, // char* type
+ kSubAttrWebvttCueLine, // float type
+ kSubAttrWebvttCueLineNum, // int type
+ kSubAttrWebvttCueLineAlign, // int type
+ kSubAttrWebvttCueAlign, // int type
+ kSubAttrWebvttCueSize, // float type
+ kSubAttrWebvttCuePosition, // float type
+ kSubAttrWebvttCuePositionAlign, // int type
+ kSubAttrWebvttCueVertical, // int type
+ kSubAttrTimestamp,
+ kSubAttrExtsubIndex, // File index of external subtitle
+ kSubAttrTypeNone
};
+enum class SubtitleType {
+ kText,
+ kPicture,
+ kInvalid
+};
+
+struct SubtitleAttr {
+ explicit SubtitleAttr(const SubtitleAttrType _type,
+ const uint32_t _start_time, const uint32_t _stop_time,
+ const boost::any _value, const int _extsub_index)
+ : type(_type),
+ start_time(_start_time),
+ stop_time(_stop_time),
+ value(_value),
+ extsub_index(_extsub_index) {}
+ const SubtitleAttrType type = kSubAttrTypeNone;
+ const uint32_t start_time = std::numeric_limits<uint32_t>::max();
+ const uint32_t stop_time = std::numeric_limits<uint32_t>::max();
+ const boost::any value;
+ const int extsub_index = -1;
+};
+using SubtitleAttrList = std::list<SubtitleAttr>;
+using SubtitleAttrListPtr = std::unique_ptr<SubtitleAttrList>;
+
} // namespace trackrenderer
} // namespace plusplayer
#include <string.h>
#undef LOG_TAG
-#define LOG_TAG "PLUSPLAYER"
+#define LOG_TAG "TRACKRENDERER"
#ifndef __MODULE__
#define __MODULE__ \
+++ /dev/null
-//
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_UTILS_PRODUCT_CFG_H__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_UTILS_PRODUCT_CFG_H__
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-enum class ProductType { kTv, kAv };
-// enum class ChipType { kKantM };
-
-namespace product_cfg {
-
-constexpr ProductType GetProductType() {
-#ifdef IS_AV_PRODUCT
- return ProductType::kAv;
-#else
- return ProductType::kTv;
-#endif
-}
-
-} // namespace product_cfg
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_UTILS_PRODUCT_CFG_H__
#include "Ecore_Wl2.h"
#include "Evas.h"
#include "gst/video/videooverlay.h"
+
#include "trackrenderer/core/display.h"
#include "trackrenderer/core/gstobject_guard.h"
const int x, const int y, const int w, const int h);
bool SetDisplay(const DisplayType& type, const uint32_t surface_id,
const int x, const int y, const int w, const int h);
- bool SetDisplaySubsurface(const DisplayType& type,
- Ecore_Wl2_Subsurface* ecore_wl2_subsurface,
- const int x, const int y, const int w, const int h);
bool SetDisplayRoi(const Geometry& roi);
bool SetDisplayCropArea(const CropArea& area);
- bool ResizeRenderRect(const RenderRect& rect);
void SetVisible(bool is_visible) { visible_ = is_visible; }
bool Update(GstElement* videosink);
bool UpdateVisible(GstElement* videosink);
- bool UpdateCropArea(GstElement* videosink);
- void GetDisplayCropArea(CropArea* area);
void GetDisplay(DisplayType* type, Geometry* area) {
*type = type_;
*area = window_;
void SetVideoQualityMode(const uint32_t mode) { qualitymode_ = mode; }
private:
- bool SetDisplay_(const DisplayType& type, wl_surface* wl_surface, const int x,
- const int y, const int w, const int h);
- wl_surface* GetWlSurface_(Ecore_Wl2_Window* ecore_wl2_window);
+ bool SetDisplay_(const DisplayType& type, Ecore_Wl2_Window* ecore_wl2_window,
+ const int x, const int y, const int w, const int h);
private:
uint32_t surface_id_ = 0;
bool visible_ = true;
std::mutex settings_mutex_;
gstguard::GstGuardPtr<GstCaps> video_quality_info_caps_;
- bool has_parent_surface_ = false;
};
} // namespace trackrenderer
ErrorType HandleError(GstMessage* message, const bool is_music_content);
-void HandleErrorMsg(GstMessage* message, gchar** error_msg);
-
} // namespace trackrenderer
} // namespace plusplayer
+++ /dev/null
-//
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_MANAGER_H__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_MANAGER_H__
-
-#include <stdint.h>
-
-#include <bitset>
-#include <future>
-#include <mutex>
-
-#include "trackrenderer/core/latency.h"
-#include "trackrenderer/core/pipeline.hpp"
-#include "trackrenderer/core/track.h"
-#include "trackrenderer/latency_status_listener.h"
-#include "trackrenderer/core/elements.h"
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-class LatencyManager {
-
- public:
- explicit LatencyManager(LatencyStatusListener* listener);
- ~LatencyManager();
-
- enum class UpdatePacketStatus {
- kSubmit,
- kFlush,
- kMax
- };
-
- void SetVideoMidLatencyThreshold(const unsigned int threshold);
- void SetAudioMidLatencyThreshold(const unsigned int threshold);
- void SetVideoHighLatencyThreshold(const unsigned int threshold);
- void SetAudioHighLatencyThreshold(const unsigned int threshold);
- void SetCatchUpSpeed(const CatchUpSpeed& level);
- void SetPipeline(Pipeline<Elements>* pipeline);
- void UnsetPipeline();
- void GetVideoLatencyStatus(LatencyStatus* status);
- void GetAudioLatencyStatus(LatencyStatus* status);
- void UpdateVideoFrameStatus(UpdatePacketStatus status);
-
- private:
- int CalculateDropRate_();
- LatencyStatus GetVideoLatencyStatus_(const unsigned int latency);
- LatencyStatus GetAudioLatencyStatus_(const unsigned int latency);
- void LatencyCheckerTask_();
- void HandleVideoLatency_(const unsigned int video_latency);
- void HandleAudioLatency_(const unsigned int audio_latency);
- void StartLatencyChecker_();
-
- private:
- enum class CheckerPrecondition {
- kSetThreshold = 0,
- kSetPipeline,
- kMax
- };
-
- unsigned int video_mid_latency_threshold_ = UINT32_MAX;
- unsigned int audio_mid_latency_threshold_ = UINT32_MAX;
- unsigned int video_high_latency_threshold_ = UINT32_MAX;
- unsigned int audio_high_latency_threshold_ = UINT32_MAX;
- unsigned int submitted_video_frames_ = 0;
- CatchUpSpeed speed_level_ = CatchUpSpeed::kNone;
- LatencyStatus video_latency_status_ = LatencyStatus::kLow;
- LatencyStatus audio_latency_status_ = LatencyStatus::kLow;
- LatencyStatusListener* event_listener_ = nullptr;
- std::future<void> latency_checker_task_;
- std::bitset<static_cast<int>(CheckerPrecondition::kMax)>
- checker_precondition_;
- bool is_stopped_ = false;
- std::mutex pipeline_m_;
- Pipeline<Elements>* pipeline_ = nullptr;
-};
-} // namespace trackrenderer
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_MANAGER_H__
+++ /dev/null
-//
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_STATUS_LISTENER_H__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_STATUS_LISTENER_H__
-
-#include "trackrenderer/core/track.h"
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-class LatencyStatusListener {
- public:
- virtual ~LatencyStatusListener() {}
- virtual void OnVideoLatencyStatus(const LatencyStatus& latency_status) = 0;
- virtual void OnAudioLatencyStatus(const LatencyStatus& latency_status) = 0;
- virtual void OnVideoHighLatency() = 0;
- virtual void OnAudioHighLatency() = 0;
-};
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_STATUS_LISTENER_H__
\ No newline at end of file
#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCE_H__
#define __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCE_H__
-#include <string>
-
#include "trackrenderer/core/track.h"
namespace plusplayer {
namespace trackrenderer {
-
-enum class RscType { kVideoRenderer };
+using ResourceHandle = void*;
enum class ResourceCategory {
kVideoDecoder,
- kVideoDecoderSub,
kVideoRenderer,
- kVideoRendererSub,
- kVideoRendererSub2,
- kVideoRendererSub3,
- kAudioDecoder,
- kAudioDecoderSub,
- kAudioRenderer,
- kAudioRendererSub
-};
-
-enum class AllocatedState { kFailed, kSuccess, kSkipped };
-
-enum class RscAllocPolicy {
- kRscAllocExclusive,
- kRscAllocConditional,
};
struct ResourceProperty {
ResourceCategory category = ResourceCategory::kVideoDecoder;
Track track;
- bool use_sw = false;
bool is_vr360 = false;
- bool is_dual_sound = false;
- bool is_multiview = false;
- bool is_ndecoding = false;
- RscAllocPolicy rsc_alloc_policy = RscAllocPolicy::kRscAllocExclusive;
};
-constexpr char kSwDecoderComponentName[] = "FFMPEG.SW.Decoder";
-constexpr char kPulseSinkComponentName[] = "Pulse.Audio.Out";
-constexpr char kSkippedResource[] = "SKIP";
-
class Resource {
public:
- Resource(const ResourceProperty& property, const std::string& componentname)
- : property_(property), componentname_(componentname) {}
- Resource(const ResourceProperty& property, int deviceid,
- const std::string& componentname)
+ Resource(ResourceProperty property, ResourceHandle res)
: property_(property),
- deviceid_(deviceid),
- componentname_(componentname) {}
- Resource(const ResourceProperty& property, AllocatedState state)
- : property_(property), state_(state) {}
- const ResourceCategory& GetResourceCategory() const {
- return property_.category;
- }
- const int& GetDeviceId() const { return deviceid_; }
- const std::string& GetComponentName() const { return componentname_; }
- const AllocatedState& GetAllocatedState() const { return state_; }
+ resource_(res){}
+ const ResourceCategory& GetResourceCategory() const { return property_.category; }
+ ResourceHandle GetResourceHandle() const { return resource_; }
private:
const ResourceProperty property_;
- const int deviceid_ = 0;
- const std::string componentname_;
- const AllocatedState state_ = AllocatedState::kSuccess;
+ ResourceHandle resource_;
};
} // namespace trackrenderer
#include <list>
#include <mutex>
-#include <string>
-
-#include "rm_api.h"
+#include "mm_resource_manager.h"
#include "trackrenderer/core/track.h"
#include "trackrenderer/resource.h"
#include "trackrenderer/resource_conflict_listener.h"
namespace trackrenderer {
-using ResourceManagerHandle = int;
+using ResourceManagerHandle = void*;
constexpr int kMaxUhd8kWidth = 7680;
constexpr int kMaxUhd8kHeight = 4320;
explicit ResourceManager(ResourceConflictListener* listener);
~ResourceManager();
- void SetAppId(const std::string& appid);
- bool Alloc(const std::list<ResourceProperty>& properties);
- bool Dealloc();
- bool Dealloc(const ResourceCategory type);
- std::string GetComponentName(const ResourceCategory type);
- int GetRawHandle();
- AllocatedState GetAllocatedState(const ResourceCategory type);
- bool IsMainDevice(const ResourceCategory& type);
- int GetDeviceId(const ResourceCategory& type);
- bool NeedPulseResource(const ResourceProperty& property);
- bool IsAudioFocused();
-
- private:
- bool Alloc_(const ResourceProperty& property);
- bool AllocPulseResource_(const ResourceProperty& property);
- bool AllocSwDecoderResource_(const ResourceProperty& property);
- bool AllocHWResource_(const ResourceProperty& property);
- bool TryAllocHWResource_(const ResourceProperty& property,
- const rm_category_request_s& req);
- int GetCategoryOption_(const rm_rsc_category_e& category_id,
- const ResourceProperty& property);
- AllocatedState MakeCategoryRequest_(const ResourceProperty& property,
- rm_category_request_s* req);
+ bool Acquire(const std::list<ResourceProperty>& properties);
+ bool Release();
+ bool Release(const ResourceCategory type);
private:
- static rm_cb_result ResourceConflictCallback_(ResourceManagerHandle rmhandle,
- rm_callback_type eventtype,
- rm_device_request_s* info,
- void* userdata);
+ static int ResourceConflictCallback_(
+ ResourceManagerHandle rmhandle, ResourceHandle res, void *userdata);
private:
ResourceManagerHandle resourcemanager_handle_ = 0;
+
std::list<Resource> resourcelist_;
std::mutex control_lock_;
ResourceConflictListener* resourceconflict_listener_ = nullptr;
- std::string app_id_ = "";
}; // class ResourceManager
} // namespace trackrenderer
+++ /dev/null
-//
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_SUBTITLE_ATTR_PARSER_H__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_SUBTITLE_ATTR_PARSER_H__
-
-#include <gst/gst.h>
-
-#include <boost/core/noncopyable.hpp>
-
-#include "trackrenderer/core/subtitle_attr.h"
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-class SubtitleAttrParser : private boost::noncopyable {
- public:
- explicit SubtitleAttrParser(GstBuffer* buf) : gstbuf_(buf) {}
- SubtitleAttrListPtr Parse();
-
- private:
- GstBuffer* gstbuf_ = nullptr;
-};
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif //__PLUSPLAYER_SRC_TRACKRENDERER_CORE_SUBTITLE_ATTR_PARSER_H__
\ No newline at end of file
#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_H__
#define __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_H__
-#include <gst/gst.h>
-#include <gst/video/video-info.h>
-
#include <boost/core/noncopyable.hpp>
#include <condition_variable> // std::condition_variable
#include <functional>
#include <string>
#include <vector>
-#ifndef SOUNDBAR_PRODUCT
-#include "avoc.h"
-#endif
+#include <gst/video/video-info.h>
+#include "gst/gst.h"
-#include "trackrenderer/audio_controller/audio_easing_controller.h"
-#include "trackrenderer/audio_controller/resyncaudio_policy.h"
#include "trackrenderer/core/attribute.hpp"
#include "trackrenderer/core/buffer.h"
#include "trackrenderer/core/decoderinputbuffer.h"
#include "trackrenderer/core/display.h"
#include "trackrenderer/core/drm.h"
-#include "trackrenderer/core/elements.h"
#include "trackrenderer/core/error.h"
#include "trackrenderer/core/event.h"
#include "trackrenderer/core/gstcaps_builder.h"
-#include "trackrenderer/core/latency.h"
-#include "trackrenderer/core/picturequality.h"
#include "trackrenderer/core/pipeline.hpp"
-#include "trackrenderer/core/screen_saver.h"
#include "trackrenderer/core/stream.h"
-#include "trackrenderer/core/subtitle_attr.h"
#include "trackrenderer/core/track.h"
-#include "trackrenderer/latency_manager.h"
-#include "trackrenderer/latency_status_listener.h"
#include "trackrenderer/resource.h"
#include "trackrenderer/resource_conflict_listener.h"
#include "trackrenderer/trackrenderer_attr.h"
#include "trackrenderer/trackrenderer_debug.h"
-#include "trackrenderer/vr360.h"
namespace plusplayer {
class ResourceManager;
class Display;
-class ScreenSaver;
enum class SubmitStatus {
kNotPrepared, // not prepared to get data
static const double kDefaultPlaybackRate = 1.0;
class TrackRenderer : public ResourceConflictListener,
- LatencyStatusListener,
private boost::noncopyable {
public:
using Ptr = std::unique_ptr<TrackRenderer>;
static Ptr Create() { return Ptr(new TrackRenderer); }
public: // Types
- using AudioStartCbHandle = std::uint32_t;
- using AudioStopCbHandle = std::uint32_t;
- using AudioResyncCbHandle = std::uint32_t;
- using VideoStartCbHandle = std::uint32_t;
- using VideoStopCbHandle = std::uint32_t;
- // LCOV_EXCL_START
class EventListener {
public:
virtual ~EventListener() {}
virtual void OnError(const ErrorType& err_code) {}
- virtual void OnErrorMsg(const ErrorType& error_code, char* error_msg){};
virtual void OnResourceConflicted() {}
virtual void OnSeekDone() {}
virtual void OnFlushDone() {}
virtual void OnEos() {}
- virtual void OnFirstDecodingDone() {}
virtual void OnEvent(const EventType& event, const EventMsg& msg_data) {}
virtual void OnSubtitleData(const DecoderInputBufferPtr& buf,
const SubtitleType& type) {}
virtual void OnBufferStatus(const TrackType& type,
const BufferStatus& status) {}
virtual void OnSeekData(const TrackType& type, const uint64_t offset) {}
- virtual void OnMediaPacketGetTbmBufPtr(void** tbm_ptr,
- bool is_scale_change) {}
virtual void OnMediaPacketVideoDecoded(const DecodedVideoPacket& packet) {}
- virtual void OnMediaRawPacketVideoDecoded(
- DecodedVideoRawModePacket& packet) {}
- virtual void OnVideoDecoderUnderrun() {}
- virtual void OnVideoLatencyStatus(const LatencyStatus& latency_status) {}
- virtual void OnAudioLatencyStatus(const LatencyStatus& latency_status) {}
- virtual void OnVideoHighLatency() {}
- virtual void OnAudioHighLatency() {}
- virtual void OnMultiviewStartVideo() {}
- virtual void OnMultiviewStopVideo() {}
};
- // LCOV_EXCL_STOP
enum class State { kInit, kWorking, kResourceConflicted, kStopped };
bool Resume();
bool SetTrack(const std::vector<Track>& trackinfo);
void SetIniProperty(const std::map<std::string, bool>& Properties);
+ void SetIniElement(const std::map<std::string, std::string>& elements);
bool Seek(uint64_t time_millisecond, double playback_rate);
bool Seek(uint64_t time_millisecond, double playback_rate, bool audio_mute);
bool SetPlaybackRate(double playback_rate, bool audio_mute);
bool GetPlayingTime(uint64_t* curtime_in_msec);
bool GetDroppedFrames(void* frame_counts);
- bool GetDroppedFramesForCatchup(TrackType type, void* frame_counts);
bool Deactivate(TrackType type);
bool Activate(TrackType type, const Track& track);
bool SubmitPacket(const DecoderInputBufferPtr& data,
}
bool SetMatroskaColorInfo(const std::string& color_info);
void DrmLicenseAcquiredDone(TrackType type);
+ void SetDrmLicenseKey(TrackType type, const std::string& key);
bool SetDisplayMode(const DisplayMode& mode);
bool SetDisplayRotate(const DisplayRotation& rotate);
void GetDisplayRotate(DisplayRotation* rotation);
bool SetDisplay(const DisplayType& type, void* obj);
bool SetDisplay(const DisplayType& type, void* ecore_wl2_window, int x, int y,
int w, int h);
- bool SetDisplaySubsurface(const DisplayType& type, void* ecore_wl2_subsurface,
- int x, int y, int w, int h);
bool SetDisplayRoi(const Geometry& roi);
bool SetVideoRoi(const CropArea& area);
- bool ResizeRenderRect(const RenderRect& rect);
bool SetDisplayVisible(bool is_visible);
void GetDisplay(DisplayType* type, Geometry* area);
void GetDisplayMode(DisplayMode* mode);
bool SetVolume(const int& volume);
bool GetVolume(int* volume);
void OnResourceConflicted() override;
- void OnVideoLatencyStatus(const LatencyStatus& latency_status) override;
- void OnAudioLatencyStatus(const LatencyStatus& latency_status) override;
- void OnVideoHighLatency() override;
- void OnAudioHighLatency() override;
+
void RegisterListener(EventListener* listener);
void SetVideoStillMode(const StillMode& type) { still_mode_type_ = type; }
void SetAttribute(const Attribute& attr, const boost::any& value);
State GetState() { return state_; }
void SetAppId(const std::string& app_id);
void SetAppInfo(const PlayerAppInfo& app_info);
- void FlushAppsrc(TrackType type, bool setbyuser);
- void SetVideoFrameBufferType(DecodedVideoFrameBufferType type);
- void SetVideoFrameBufferScaleResolution(const uint32_t& target_width,
- const uint32_t& target_height);
- bool SetDecodedVideoFrameRate(const Rational& request_framerate);
+ void FlushAppsrc(TrackType type);
+ void SetVideoFrameBufferType(DecodedVideoFrameBufferType type) {
+ decoded_buffer_type_ = type;
+ }
bool RenderVideoFrame();
- bool SetAiFilter(void* aifilter);
- void SetAlternativeAudioResource(const boost::any& value);
- void SetCatchUpSpeed(const CatchUpSpeed& level);
- void GetVideoLatencyStatus(LatencyStatus* status);
- void GetAudioLatencyStatus(LatencyStatus* status);
- void SetVideoMidLatencyThreshold(const unsigned int threshold);
- void SetAudioMidLatencyThreshold(const unsigned int threshold);
- void SetVideoHighLatencyThreshold(const unsigned int threshold);
- void SetAudioHighLatencyThreshold(const unsigned int threshold);
- bool InitAudioEasingInfo(const uint32_t& init_volume,
- const uint32_t& init_elapsed_time,
- const AudioEasingInfo& info);
- bool UpdateAudioEasingInfo(const AudioEasingInfo& info);
- bool GetAudioEasingInfo(uint32_t* current_volume, uint32_t* elapsed_time,
- AudioEasingInfo* info);
- bool StartAudioEasing();
- bool StopAudioEasing();
- bool GetVirtualRscId(const RscType type, int* virtual_id);
- bool SetAdvancedPictureQualityType(const AdvPictureQualityType type);
- bool SetResourceAllocatePolicy(const RscAllocPolicy policy);
- bool SetVideoRendererType(const ResourceCategory video_renderer_type);
- void SetVideoParDar(uint64_t time_millisecond, uint32_t par_n, uint32_t par_d,
- uint32_t dar_n, uint32_t dar_d);
private:
+ enum class Elements {
+ kPipeline, // must be the first
+ kAppSrcVideo,
+ kAppSrcAudio,
+ kAppSrcSubtitle,
+ kDrmVideo,
+ kDrmAudio,
+ kDecVideo,
+ kDecAudio,
+ kSinkVideo,
+ kAudioConvert,
+ kCapsFillterDefault,
+ kCapsFillter2,
+ kAudioResample,
+ kScaleTempo,
+ kSinkAudio,
+ kSinkSubtitle,
+ kBinVideo,
+ kBinAudio,
+ kBinSubtitle,
+ kSinkCaption,
+ kQueueCaption,
+ kFakeSinkAudio,
+ kVideoConvert,
+ kParseVideo,
+ kParseAudio,
+ kVideoQueue,
+ kCCExtractor,
+ kCCConverter,
+ kCCCapsFilter,
+ kMaxElements // must be the last
+ };
+
enum VolumeLevel {
kVolumeNone = -1,
kVolumeMin = 0,
kLowLatencyModeNone = 0x0000,
kLowLatencyModeAudio = 0x0001,
kLowLatencyModeVideo = 0x0010,
- kLowLatencyModeVideoDistortionConcealment = kLowLatencyModeVideo | 0x0020,
kLowLatencyModeDisableAVSync = 0x0100,
- kLowLatencyModeDisablePreroll = 0x0200,
kLowLatencyModeDisableVideoQuality = 0x1000
};
- enum class DropMode {
- kDropModeNone = 0,
- kDropModeAccordingToRate,
- kDropModeAccordingToTable,
- };
-
enum class SubState {
kUnknown,
kPaused,
bool is_enough_data = false;
bool need_update_segment = true;
std::function<bool(const Track*)> create_pipeline;
- Track* track = nullptr;
+ const Track* track = nullptr;
};
struct AttributeValue {
uint64_t time = 0;
};
- struct DropContext {
- std::mutex drop_mutex;
- Rational track_fps;
- Rational request_fps;
- bool fps_changed = false;
- DropMode drop_mode = DropMode::kDropModeNone;
- uint32_t drop_rate = 0;
- uint32_t base_num = 0;
- };
-
public:
using TrackRendererAttributeSetter = AttributeSetter<Elements>;
using TrackRendererAttributeGetter = AttributeGetter<Elements>;
static void GstDecodedVideoCopyBufferCb_(GstElement* element,
GstBuffer* buffer, GstPad* pad,
void* userdata);
- static void GstDecodedVideoRawBufferCb_(GstElement* element,
- GstBuffer* buffer, GstPad* pad,
- void* userdata);
- static void GstDecodedVideoScaleBufferCb_(GstElement* element,
- GstBuffer* buffer, GstPad* pad,
- void* userdata);
- static void GstAiFilterResultCb_(GstElement* element, GstStructure* structure,
- void* userdata);
static AttributesByElement InitAttributeByElementType_();
- static void MultiviewStartAudioCb_(int player_id, void* data);
- static void MultiviewStopAudioCb_(int player_id, void* data);
- static void MultiviewResyncAudioCb_(int player_id, void* data);
- static void MultiviewStartVideoCb_(int player_id, void* data);
- static void MultiviewStopVideoCb_(int player_id, void* data);
- static void VconfCb_(const std::string& name, const std::string& value,
- void* userdata);
static GstPadProbeReturn GstSrcPadProbeBlockCb_(GstPad* pad,
GstPadProbeInfo* info,
gpointer userdata);
static GstPadProbeReturn GstPadProbeVideoPeekBlockCb_(GstPad* pad,
GstPadProbeInfo* info,
gpointer userdata);
- static GstPadProbeReturn GstPadProbeVideoDecodedCb_(GstPad* pad,
- GstPadProbeInfo* info,
- gpointer userdata);
- static GstPadProbeReturn GstPadProbeVideoDecInputCb_(GstPad* pad,
+ static GstPadProbeReturn GstPadProbeCapsEventCb_(GstPad* pad,
+ GstPadProbeInfo* info,
+ gpointer userdata);
+
+ static GstPadProbeReturn GstPadProbeAppsrcEventCb_(GstPad* pad,
GstPadProbeInfo* info,
gpointer userdata);
- bool GetResource_(const TrackType& type);
+ bool GetResource_();
bool CreatePipeline_();
void CreateAppSrc_(TrackType type, const std::string& mimetype);
- void CreateDrmElement_(const Track& track);
- const char* GetAudioSinkPluginName_(bool swdecoder,
- const std::string& mimetype);
- void CreateAudioSink_(const std::string& sink_name);
- void CreateVideoDecoder_(const char* dec_name);
- bool CreateVideoSink_();
- void SetPropertyForAiFilter_();
- void SetPropertyForDecodedVideoBufferWithDisplay_();
- void SetPropertyForDecodedVideoBufferWithoutDisplay_();
- void SetPropertyForDecodedVideoBuffer_();
bool CreateVideoPipeline_(const Track* track);
+ bool CreateDecodedVideoPipeline_(const Track* track);
bool CreateAudioPipeline_(const Track* track);
- bool CreateSwAudioPipeline_(const Track* track);
bool CreateRawAudioPipeline_(const Track* track);
bool CreateSubtitlePipeline_(const Track* track);
- bool NeedAvocPlayerRegister_();
- bool AvocPlayerRegister_();
- bool AvocPlayRequest_();
- bool AvocPlayerUnRegister_();
- bool AddAiFilter_(void* aifilter);
- void RemoveAiFilter_();
bool ReleaseResource_();
bool ControlDropRate_(uint64_t packet_pts, SubmitStatus* status);
bool RemoveDownstreamOfAppsrc_(TrackType type);
const char* GetDecoderPluginName_(TrackType type,
const std::string& mimetype);
- void UpdateStartSegment_(GstClockTime start_time, const TrackType& type);
- SubtitleType GetSubtitleType_(const GstBuffer* buffer);
+ TrackType GetBaseTrackType_();
void GstElementCreatedCb_(Elements element);
void SetDefaultAttributeValue_();
void SetAttribute_(const TrackRendererAttributeBinder& binder,
void SetVolume_();
bool ActivateAudio_();
bool DeactivateAudio_();
- void FlushDownStream_(Elements element, const char* key, gboolean reset_time);
+ void FlushAudioDownStream_(Elements element);
void InitConfigSetterTable_();
bool SetAccurateSeekMode_(const boost::any& value);
bool SetLowLatencyMode_(const boost::any& value);
bool SetWindowStandAloneMode_(const boost::any& value);
bool SetVideoFramePeekMode_(const boost::any& value);
void GstElementLowLatency_(const TrackType& type);
- void CreateTbmBufferManager_();
- void SetVr360GpuModeSecure_(bool set);
- void SetSequentialMode_();
- void SetDirectCrop_(const std::string& app_id);
+ void CreateTbmBufferManager_(const Track* track);
+ void SetSequentialMode_(const std::string& app_id);
void GetResolutionInfo_(EventMsg* event_msg);
bool SetUnlimitedMaxBufferMode_(const boost::any& value);
bool SetVideoPreDisplayMode_(const boost::any& value);
bool SetStartRenderingTime_(const boost::any& value);
bool SetFmmMode_(const boost::any& value);
- bool SetAlternativeVideoResource_(const boost::any& value);
- bool SetVideoDecodingMode_(const boost::any& value);
- bool SetLateVideoFrameDropMode_(const boost::any& value);
void SetVideoQualityInfo_();
void CompleteSeeking_(void);
- bool IsSegmentUpdated_() const;
bool HasSubtitleOnly_() const;
- void SetDefaultAppSrcSignals_(const TrackType& type);
- bool SetResourceCenterCallback_();
- bool UnsetResourceCenterCallback_();
- void SetVconfCb_();
- void UnsetVconfCb_();
- bool StopAudioEasing_();
- bool NeedSyncPause_();
- bool ResyncAudio_();
- void SetAudioOut_();
- void UpdateTrackFrameRate_(const int& framerate_num,
- const int& framerate_den);
- void UpdateDecodedDropContext_();
- bool NeedDropThisDecodedVideoBuffer_();
+ bool ActivateAudioPipeline(GstCaps* caps);
private:
EventListener* eventlistener_ = nullptr; // eventlistener is Defaultplayer
std::mutex resource_m_;
- std::mutex internal_audio_m_;
std::condition_variable resource_cv_;
std::unique_ptr<ResourceManager> resource_manager_;
std::unique_ptr<Display> display_;
- std::unique_ptr<ScreenSaver> screen_saver_;
- std::unique_ptr<AudioEasingController> audio_easing_controller_;
- ResourceCategory video_decoder_id_ = ResourceCategory::kVideoDecoder;
- ResourceCategory video_renderer_id_ = ResourceCategory::kVideoRenderer;
- ResourceCategory audio_out_id_ = ResourceCategory::kAudioRenderer;
- ResourceCategory audio_decoder_id_ = ResourceCategory::kAudioDecoder;
- RscAllocPolicy rsc_alloc_policy_ = RscAllocPolicy::kRscAllocExclusive;
- AudioStartCbHandle audio_start_cb_id_ = 0;
- AudioStopCbHandle audio_stop_cb_id_ = 0;
- AudioResyncCbHandle audio_resync_cb_id_ = 0;
- VideoStartCbHandle video_start_cb_id_ = 0;
- VideoStopCbHandle video_stop_cb_id_ = 0;
- int avoc_id_ = -1;
- bool need_avoc_register = false;
GstCapsBuilder caps_builder_;
std::map<std::string, bool> properties_;
+ std::map<std::string, std::string> ini_elements_;
std::vector<Track> trackinfo_;
TrackContext trackctx_[kTrackTypeMax];
bool is_seeking_ = false;
bool is_flushing_ = false;
- gboolean is_sound_mute_ = FALSE;
+ bool is_sound_mute_ = false;
bool is_accurate_seek_ = false;
bool is_async_done_ = false;
- gboolean window_stand_alone_mode_ = FALSE;
+ bool window_stand_alone_mode_ = false;
bool is_video_frame_peek_ = false;
std::uint32_t low_latency_mode_ = 0;
bool unlimited_max_buffer_mode_ = 0;
bool video_pre_display_mode_ = false;
- gint fmm_mode_ = 0;
- std::uint32_t video_decoding_mode_ = 0x02; // seamless mode
+ bool fmm_mode_ = false;
RenderingStartTime rendering_start_time_;
int volume_ = kVolumeNone;
uint64_t last_position_ = 0;
DecodedVideoFrameBufferType decoded_buffer_type_ =
DecodedVideoFrameBufferType::kNone;
bool is_audioactivated_ = true;
- bool is_videoactivated_ = true;
- bool is_multiscreen_ = false;
std::unique_ptr<TbmBufferManager> tbm_buffer_manager_;
int use_seq_mode_ = 0;
- void* aifilter_ = nullptr;
- bool enable_direct_crop_ = false;
double playback_rate_ = kDefaultPlaybackRate;
SubState target_substate_ = SubState::kUnknown;
std::map<std::string, Config_Setter> config_setter_table_;
- bool enable_audio_track_change_ = false;
- gboolean support_audio_codec_change_ = FALSE;
- bool support_videodec_underflow_pause_ = false;
- bool need_avoc_sub_source_ = false;
-#ifndef SOUNDBAR_PRODUCT
- avoc_sub_source_e avoc_sub_source_ = AVOC_SUB_SOURCE_NONE;
-#endif
- std::unique_ptr<LatencyManager> latency_manager_;
- int virtual_scaler_id_ = -1;
- bool is_error_posted_ = false;
-
- std::unique_ptr<ResyncAudioPolicy> resync_audio_policy_;
- DisplayType display_type_ = DisplayType::kNone;
- uint32_t scale_target_width_ = 960;
- uint32_t scale_target_height_ = 540;
- bool is_scale_size_changed_ = false;
- std::mutex tbmmgr_m_;
- DropContext decoded_drop_ctx_;
- std::mutex scale_target_m_;
-
- std::unique_ptr<Vr360> vr360_;
-
- bool drop_all_late_video_ = false;
- ParDarInfo par_dar_;
- bool is_pardar_updated_ = false;
+ int64_t start_time = -1;
private:
static const Attributes kAttributes_;
/*
* NOTICE
* If there is new attribute, please write details in below documents.
- *
+ * http://wiki.vd.sec.samsung.net/display/plusplayer/TrackRenderer+Attribute
*
*/
kAudioQueueCurrentLevelByte, // std::uint64_t
kVideoMinByteThreshold, // std::uint32_t
kAudioMinByteThreshold, // std::uint32_t
- kVideoQueueMaxTime, // std::uint64_t
- kAudioQueueMaxTime, // std::uint64_t
- kVideoQueueCurrentLevelTime, // std::uint64_t
- kAudioQueueCurrentLevelTime, // std::uint64_t
- kVideoMinTimeThreshold, // std::uint32_t
- kAudioMinTimeThreshold, // std::uint32_t
- kVideoSupportRotation, // std::uint32_t
- kVideoRenderTimeOffset, // std::int64_t
- kAudioRenderTimeOffset, // std::int64_t
+ kVideoQueueMaxBuffer, // std::uint64_t
+ kAudioQueueMaxBuffer, // std::uint64_t
kMax,
};
constexpr char ConfigNameVideoPreDisplayMode[] = "video-pre-display-mode";
constexpr char ConfigNameStartRenderingTime[] = "start-rendering-time";
constexpr char ConfigNameFmmMode[] = "fmm-mode";
-constexpr char ConfigNameAlternativeVideoResource[] =
- "alternative-video-resource";
-constexpr char ConfigNameVideoDecodingMode[] = "video-decoding-mode";
-constexpr char ConfigNameLateVideoFrameDropMode[] = "late-video-frame-drop-mode";
struct TrackRendererAttrInfo {
const ValueType value_type;
{"audio-min-byte-percent",
{ValueType::kUInt32,
plusplayer::trackrenderer::Attribute::kAudioMinByteThreshold}},
- {"video-queue-max-time",
+ {"video-queue-max-buffer",
{ValueType::kUInt64,
- plusplayer::trackrenderer::Attribute::kVideoQueueMaxTime}},
- {"audio-queue-max-time",
+ plusplayer::trackrenderer::Attribute::kVideoQueueMaxBuffer}},
+ {"audio-queue-max-buffer",
{ValueType::kUInt64,
- plusplayer::trackrenderer::Attribute::kAudioQueueMaxTime}},
- {"video-current-level-time",
- {ValueType::kUInt64,
- plusplayer::trackrenderer::Attribute::kVideoQueueCurrentLevelTime}},
- {"audio-current-level-time",
- {ValueType::kUInt64,
- plusplayer::trackrenderer::Attribute::kAudioQueueCurrentLevelTime}},
- {"video-min-time-percent",
- {ValueType::kUInt32,
- plusplayer::trackrenderer::Attribute::kVideoMinTimeThreshold}},
- {"audio-min-time-percent",
- {ValueType::kUInt32,
- plusplayer::trackrenderer::Attribute::kAudioMinTimeThreshold}},
- {"video-support-rotation",
- {ValueType::kUInt32,
- plusplayer::trackrenderer::Attribute::kVideoSupportRotation}},
- {"video-render-time-offset",
- {ValueType::kInt64,
- plusplayer::trackrenderer::Attribute::kVideoRenderTimeOffset}},
- {"audio-render-time-offset",
- {ValueType::kInt64,
- plusplayer::trackrenderer::Attribute::kAudioRenderTimeOffset}}};
+ plusplayer::trackrenderer::Attribute::kAudioQueueMaxBuffer}}};
static const std::map<std::string, ValueType> kConfigInfoTable = {
{ConfigNameAccurateSeekMode, ValueType::kUInt32},
{ConfigNameUnlimitedMaxBufferMode, ValueType::kUInt32},
{ConfigNameVideoPreDisplayMode, ValueType::kUInt32},
{ConfigNameStartRenderingTime, ValueType::kUInt64},
- {ConfigNameFmmMode, ValueType::kUInt32},
- {ConfigNameAlternativeVideoResource, ValueType::kUInt32},
- {ConfigNameVideoDecodingMode, ValueType::kUInt32},
- {ConfigNameLateVideoFrameDropMode, ValueType::kUInt32}};
+ {ConfigNameFmmMode, ValueType::kUInt32}};
} // namespace trackrenderer
} // namespace plusplayer
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_ATTR_H__
\ No newline at end of file
+#endif // __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_ATTR_H__
#include <vector>
#include "trackrenderer/core/appinfo.h"
-#include "trackrenderer/core/audioeasinginfo.h"
#include "trackrenderer/core/buffer.h"
#include "trackrenderer/core/display.h"
#include "trackrenderer/core/drm.h"
#include "trackrenderer/core/error.h"
#include "trackrenderer/core/event.h"
-#include "trackrenderer/core/latency.h"
-#include "trackrenderer/core/picturequality.h"
-#include "trackrenderer/core/subtitle_attr.h"
#include "trackrenderer/core/track.h"
-#include "trackrenderer/resource.h"
#include "trackrenderer_capi/buffer.h"
#include "trackrenderer_capi/decoderinputbuffer.h"
#include "trackrenderer_capi/display.h"
#include "trackrenderer_capi/drm.h"
#include "trackrenderer_capi/error.h"
#include "trackrenderer_capi/iniproperty.h"
-#include "trackrenderer_capi/latency.h"
#include "trackrenderer_capi/track.h"
#include "trackrenderer_capi/trackrenderer_capi.h"
-#include "trackrenderer_capi/trackrenderer_internal.h"
namespace plusplayer {
#endif
void MakeDrmProperty(drm::Property* drm_property,
const TrackRendererDrmProperty& properties);
-void MakeGeometry(Geometry* output, const TrackRendererGeometry& input);
-void MakeCropArea(CropArea* output, const TrackRendererCropArea& input);
-void MakeRenderRect(RenderRect* output, const TrackRendererRenderRect& input);
+void MakeGeometry(Geometry* roi, const TrackRendererGeometry& geometry);
+void MakeCropArea(CropArea* area, const TrackRendererCropArea& crop);
std::map<std::string, bool> MakeIniProperty(
TrackRendererIniProperty* properties, int size);
+std::map<std::string, std::string> MakeIniElement(
+ TrackRendererIniElement* elements, int size);
std::vector<Track> MakeTrack(const TrackRendererTrack* trackrenderertrack,
const int size);
-std::vector<Track> MakeTrackFromTrackHandle(
- const TrackRendererTrackHandle* track_handle, const int size);
void MakeTrackRendererGeometry(TrackRendererGeometry* geometry,
const Geometry& roi);
#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
const DecodedVideoPacket& packet);
DecodedVideoFrameBufferType ConvertToVideoFrameBufferType(
const TrackRendererDecodedVideoFrameBufferType& type);
-DecodedVideoFrameBufferType ConvertToVideoFrameBufferTypeExt(
- const TrackRendererDecodedVideoFrameBufferTypeExt& type);
-CatchUpSpeed ConvertToCatchUpSpeed(const TrackRendererCatchUpSpeed& level);
-TrackRendererLatencyStatus ConvertToTrackrendererLatencyStatus(
- const LatencyStatus& status);
-
-AudioEasingType ConvertToAudioEasingType(
- const TrackRendererAudioEasingType& type);
-TrackRendererAudioEasingType ConvertToTrackRendererAudioEasingType(
- const AudioEasingType& type);
-void MakeAudioEasingInfo(AudioEasingInfo* easing_info,
- const TrackRendererAudioEasingInfo* easing_attr);
-void MakeTrackRendererAudioEasingInfo(TrackRendererAudioEasingInfo* easing_attr,
- const AudioEasingInfo& easing_info);
-bool ConvertToRscType(const TrackRendererRscType& typevalue, RscType* type);
-bool ConvertToAdvPictureQualityType(
- const TrackRendererAdvPictureQualityType& typevalue,
- AdvPictureQualityType* type);
-void MakeRational(Rational* rational_info,
- const TrackRendererRational& rational_attr);
-bool ConvertToRscAllocPolicy(const TrackRendererRscAllocPolicy& policyvalue,
- RscAllocPolicy* policy);
-bool ConvertToVideoRendererType(
- const TrackRendererVideoRendererType& renderer_type,
- ResourceCategory* rsc_category);
} // namespace capi_utils
} // namespace trackrenderer
+++ /dev/null
-//
-// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_VCONF_H__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_VCONF_H__
-
-#include <boost/core/noncopyable.hpp>
-#include <list>
-#include <map>
-#include <string>
-#include <utility>
-#include <mutex>
-#include <vector>
-
-#include "vconf.h"
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-constexpr char kMultiscreenInfoVconf[] = "memory/multiscreen/info";
-constexpr char kPowerAnimationVconf[] = "memory/welcome_mode/power_animation";
-constexpr char kTV2MobileStateVconf[] =
- "memory/menu/network/screenmirroring/smsrc_status";
-
-typedef void (*vconf_cb)(const std::string& name, const std::string& value,
- void* userdata);
-
-class Vconf : private boost::noncopyable {
- public:
- using VconfPair = std::pair<vconf_cb, void*>;
- using VconfCbList = std::list<VconfPair>;
- using VconfMap = std::map<std::string, VconfCbList>;
-
- Vconf(Vconf const&) = delete;
- Vconf(Vconf&&) = delete;
- Vconf& operator=(Vconf const&) = delete;
- Vconf& operator=(Vconf&&) = delete;
-
- static Vconf& Instance() {
- static Vconf instance;
- return instance;
- }
-
- bool IsMultiscreenMode();
- void SetVconfsCb(const std::vector<std::string>& names,
- vconf_cb callback, void* userdata);
- void UnsetVconfsCb(const std::vector<std::string>& names,
- vconf_cb callback, void* userdata);
-
- private:
- Vconf();
- ~Vconf();
- void SetVconfCb_(const std::string& name, vconf_cb callback,
- void* userdata);
- void UnsetVconfCb_(const std::string& name, vconf_cb callback,
- void* userdata);
- static void VconfCb_(keynode_t* key, void* userdata);
- void Notify_(const std::string& name, const std::string& value);
- bool ParseMlsVconf_(const char* json);
-
- private:
- std::mutex vconf_m_;
- VconfMap vconf_map_;
-};
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_VCONF_H__
+++ /dev/null
-//
-// @ Copyright [2021] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_VR360_POLICY_H__
-#define __PLUSPLAYER_SRC_TRACKRENDERER_VR360_POLICY_H__
-
-#include <boost/core/noncopyable.hpp>
-#include <string>
-#include <utility>
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-using Vr360TzHandle = void *;
-using Vr360Initialize = int (*)(Vr360TzHandle *handle);
-using Vr360Finalize = int (*)(Vr360TzHandle handle);
-using Vr360SetGpuMode = int (*)(Vr360TzHandle handle, int mode);
-
-class Vr360 : private boost::noncopyable {
- public:
- enum class GpuMode {
- kVr360GpuModeSecure = 0x301, /**< Give GPU secure property */
- kVr360GpuModeNonSecure, /**< Take secure property from GPU */
- };
-
- explicit Vr360();
- ~Vr360();
-
- void Vr360TzSetGpuMode(bool set);
-
- private:
- Vr360TzHandle vr360_tz_handle_ = nullptr;
-};
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-
-#endif // __PLUSPLAYER_SRC_TRACKRENDERER_VR360_POLICY_H__
\ No newline at end of file
+++ /dev/null
-//
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#include <cassert>
-
-#include "trackrenderer/core/utils/log.h"
-#include "trackrenderer/latency_manager.h"
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-LatencyManager::LatencyManager(LatencyStatusListener* listener)
- : event_listener_(listener) {
- assert(listener && "listener is nullptr!!");
-}
-
-LatencyManager::~LatencyManager() {
- if (latency_checker_task_.valid()) {
- is_stopped_ = true;
- latency_checker_task_.wait();
- }
- TRACKRENDERER_INFO("Bye~");
-}
-
-void LatencyManager::SetVideoMidLatencyThreshold(const unsigned int threshold) {
- video_mid_latency_threshold_ = threshold;
- TRACKRENDERER_INFO("Video MidLatencyThreshold : %d",
- video_mid_latency_threshold_);
- checker_precondition_.set(
- static_cast<int>(CheckerPrecondition::kSetThreshold));
- StartLatencyChecker_();
-}
-
-void LatencyManager::SetAudioMidLatencyThreshold(const unsigned int threshold) {
- audio_mid_latency_threshold_ = threshold;
- TRACKRENDERER_INFO("Audio MidLatencyThreshold : %d",
- audio_mid_latency_threshold_);
- checker_precondition_.set(
- static_cast<int>(CheckerPrecondition::kSetThreshold));
- StartLatencyChecker_();
-}
-
-void LatencyManager::SetVideoHighLatencyThreshold(
- const unsigned int threshold) {
- video_high_latency_threshold_ = threshold;
- TRACKRENDERER_INFO("Video HighLatencyThreshold : %d",
- video_high_latency_threshold_);
- checker_precondition_.set(
- static_cast<int>(CheckerPrecondition::kSetThreshold));
- StartLatencyChecker_();
-}
-
-void LatencyManager::SetAudioHighLatencyThreshold(
- const unsigned int threshold) {
- audio_high_latency_threshold_ = threshold;
- TRACKRENDERER_INFO("Audio HighLatencyThreshold : %d",
- audio_high_latency_threshold_);
- checker_precondition_.set(
- static_cast<int>(CheckerPrecondition::kSetThreshold));
- StartLatencyChecker_();
-}
-
-void LatencyManager::SetCatchUpSpeed(const CatchUpSpeed& level) {
- speed_level_ = level;
-
- if (pipeline_) {
- if (speed_level_ != CatchUpSpeed::kNone) {
- int drop_rate = CalculateDropRate_();
- pipeline_->SetProperty(Elements::kSinkVideo, "frame-drop-rate",
- drop_rate);
- pipeline_->SetProperty(Elements::kSinkAudio, "frame-drop-rate",
- drop_rate);
- }
- }
-}
-
-void LatencyManager::GetVideoLatencyStatus(LatencyStatus* status) {
- *status = video_latency_status_;
- TRACKRENDERER_INFO("LatencyStatus is %d", static_cast<int>(*status));
-}
-
-void LatencyManager::GetAudioLatencyStatus(LatencyStatus* status) {
- *status = audio_latency_status_;
- TRACKRENDERER_INFO("LatencyStatus is %d", static_cast<int>(*status));
-}
-
-void LatencyManager::SetPipeline(Pipeline<Elements>* pipeline) {
- if (pipeline_) {
- assert(0 && "pipeline already exist");
- }
- pipeline_ = pipeline;
- checker_precondition_.set(
- static_cast<int>(CheckerPrecondition::kSetPipeline));
- StartLatencyChecker_();
-}
-
-void LatencyManager::UnsetPipeline() {
- TRACKRENDERER_ENTER;
- is_stopped_ = true;
- checker_precondition_.reset(
- static_cast<int>(CheckerPrecondition::kSetPipeline));
- std::lock_guard<std::mutex> mutex(pipeline_m_);
- pipeline_ = nullptr;
- TRACKRENDERER_LEAVE;
-}
-
-void LatencyManager::UpdateVideoFrameStatus(
- LatencyManager::UpdatePacketStatus status) {
- switch (status) {
- case LatencyManager::UpdatePacketStatus::kFlush:
- TRACKRENDERER_INFO("Flush, reset the value!");
- submitted_video_frames_ = 0;
- return;
- case LatencyManager::UpdatePacketStatus::kSubmit:
- ++submitted_video_frames_;
- return;
- default:
- TRACKRENDERER_ERROR("Wrong status:%d", static_cast<int>(status));
- }
-}
-
-void LatencyManager::StartLatencyChecker_() {
- TRACKRENDERER_ENTER;
- std::bitset<static_cast<int>(CheckerPrecondition::kMax)> precondition;
- precondition.set();
-
- if (precondition != checker_precondition_) {
- TRACKRENDERER_INFO("Can't make checker thread, precondition = %s",
- checker_precondition_.to_string().c_str());
- return;
- }
-
- if (latency_checker_task_.valid()) {
- TRACKRENDERER_INFO("checker task is already valid");
- return;
- }
-
- pipeline_->SetProperty(Elements::kAppSrcAudio, "noqueue", FALSE);
- pipeline_->SetProperty(Elements::kAppSrcAudio, "max-bytes", 0);
-
- if (speed_level_ != CatchUpSpeed::kNone) {
- int drop_rate = CalculateDropRate_();
- pipeline_->SetProperty(Elements::kSinkVideo, "frame-drop-rate", drop_rate);
- pipeline_->SetProperty(Elements::kSinkAudio, "frame-drop-rate", drop_rate);
- }
-
- latency_checker_task_ = std::async(
- std::launch::async, &LatencyManager::LatencyCheckerTask_, this);
- if (!latency_checker_task_.valid()) {
- TRACKRENDERER_ERROR("checker task is Not valid");
- return;
- }
- TRACKRENDERER_LEAVE;
-}
-
-void LatencyManager::LatencyCheckerTask_() {
- TRACKRENDERER_ENTER;
- while (!is_stopped_) {
- std::unique_lock<std::mutex> mutex(pipeline_m_);
- if (pipeline_ == nullptr) return;
-
- uint consumed_frames = 0;
- bool ret = pipeline_->GetProperty(Elements::kSinkVideo, "consumed-frames",
- &consumed_frames);
- int video_latency = submitted_video_frames_ - consumed_frames;
- if (video_latency < 0) {
- TRACKRENDERER_ERROR(
- "ERROR!! consumed_frames = %u, submitted_video_frames_ = %u",
- consumed_frames, submitted_video_frames_);
- video_latency = 0;
- }
- if (ret == true) HandleVideoLatency_(video_latency);
-
- uint audio_latency = 0;
- ret = pipeline_->GetProperty(Elements::kAppSrcAudio, "frame-count",
- &audio_latency);
- if (ret == true) HandleAudioLatency_(audio_latency);
- mutex.unlock();
-
- // TODO: How to set the sleep time.
- std::this_thread::sleep_for(std::chrono::milliseconds(50));
- }
- TRACKRENDERER_LEAVE;
-}
-
-void LatencyManager::HandleVideoLatency_(const unsigned int video_latency) {
- if (is_stopped_) return;
-
- LatencyStatus prev_video_latency_status_ = video_latency_status_;
- video_latency_status_ = GetVideoLatencyStatus_(video_latency);
- bool is_status_changed =
- video_latency_status_ != prev_video_latency_status_ ? true : false;
-
- if (is_status_changed) {
- event_listener_->OnVideoLatencyStatus(video_latency_status_);
- if (video_latency_status_ == LatencyStatus::kHigh) // To be deleted. later.
- event_listener_->OnVideoHighLatency();
-
- if (prev_video_latency_status_ == LatencyStatus::kLow) {
- pipeline_->SetProperty(Elements::kSinkVideo, "is-catchup-mode", TRUE);
- } else if (video_latency_status_ == LatencyStatus::kLow) {
- pipeline_->SetProperty(Elements::kSinkVideo, "is-catchup-mode", FALSE);
- }
- }
-}
-
-void LatencyManager::HandleAudioLatency_(const unsigned int audio_latency) {
- if (is_stopped_) return;
-
- LatencyStatus prev_audio_latency_status_ = audio_latency_status_;
- audio_latency_status_ = GetAudioLatencyStatus_(audio_latency);
- bool is_status_changed =
- audio_latency_status_ != prev_audio_latency_status_ ? true : false;
-
- if (is_status_changed) {
- event_listener_->OnAudioLatencyStatus(audio_latency_status_);
- if (audio_latency_status_ == LatencyStatus::kHigh) // To be deleted. later.
- event_listener_->OnAudioHighLatency();
-
- if (prev_audio_latency_status_ == LatencyStatus::kLow) {
- pipeline_->SetProperty(Elements::kSinkAudio, "is-catchup-mode", TRUE);
- } else if (audio_latency_status_ == LatencyStatus::kLow) {
- pipeline_->SetProperty(Elements::kSinkAudio, "is-catchup-mode", FALSE);
- }
- }
-}
-
-int LatencyManager::CalculateDropRate_() {
- int ret = 0;
- if (speed_level_ == CatchUpSpeed::kSlow) {
- // TODO
- ret = 4;
- } else if (speed_level_ == CatchUpSpeed::kMid) {
- // TODO
- ret = 3;
- } else {
- // TODO
- ret = 2;
- }
- return ret;
-}
-
-LatencyStatus LatencyManager::GetVideoLatencyStatus_(
- const unsigned int latency) {
- TRACKRENDERER_DEBUG(
- "Latency : %d, video_mid_latency_threshold : %d, "
- "video_high_latency_threshold : %d",
- latency, video_mid_latency_threshold_, video_high_latency_threshold_);
-
- if (video_mid_latency_threshold_ == UINT32_MAX) {
- if (latency < video_high_latency_threshold_) {
- return LatencyStatus::kLow;
- } else {
- return LatencyStatus::kHigh;
- }
- }
-
- if (latency < video_mid_latency_threshold_) {
- return LatencyStatus::kLow;
- } else if (latency >= video_high_latency_threshold_) {
- return LatencyStatus::kHigh;
- } else {
- return LatencyStatus::kMid;
- }
-}
-
-LatencyStatus LatencyManager::GetAudioLatencyStatus_(
- const unsigned int latency) {
- TRACKRENDERER_DEBUG(
- "Latency : %d, audio_mid_latency_threshold : %d, "
- "audio_high_latency_threshold : %d",
- latency, audio_mid_latency_threshold_, audio_high_latency_threshold_);
-
- if (audio_mid_latency_threshold_ == UINT32_MAX) {
- if (latency < audio_high_latency_threshold_) {
- return LatencyStatus::kLow;
- } else {
- return LatencyStatus::kHigh;
- }
- }
-
- if (latency < audio_mid_latency_threshold_) {
- return LatencyStatus::kLow;
- } else if (latency >= audio_high_latency_threshold_) {
- return LatencyStatus::kHigh;
- } else {
- return LatencyStatus::kMid;
- }
-}
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
//
-#include "trackrenderer/resourcemanager.h"
-
-#include <stdlib.h> // free
-
-#include <algorithm> // std::min
-#include <boost/scope_exit.hpp>
-#include <cassert> // assert()
-#include <chrono> // std::chrono
-#include <functional>
+#include <cassert> // assert()
#include <map> // std::map
-#include <stdexcept> // std::out_of_range
-#include <thread> // std::this_thread::sleep_for
-#include <unordered_map>
-
-#include "resource_center.h"
-#include "ri-api.h"
-#include "ri-module-api.h"
-#include "rm_module_api.h"
+#include "trackrenderer/resourcemanager.h"
#include "trackrenderer/core/utils/log.h"
+
namespace plusplayer {
namespace trackrenderer {
namespace internal {
-constexpr int kMaxFrameRate = 60;
-constexpr int kDefaultColorDepth = 8;
-constexpr int kDefaultSamplingFormat = 1;
-
-// clang-format off
-const std::map<std::string, std::string> MimeTypetoCodecNameConverter = {
- {"video/x-h264", "H264"}, {"video/x-h265", "HEVC"},
- {"video/mpeg1", "MPEG1"}, {"video/mpeg2", "MPEG2"},
- {"video/mpeg4", "MPEG4"}, {"video/x-msmpeg", "MPEG4"},
- {"video/x-wmv", "WMV"}, {"video/x-h263", "H263"},
- {"video/x-pn-realvideo", "RV"}, {"video/x-vp8", "VP8"},
- {"video/x-vp9", "VP9"}, {"video/x-divx", "MPEG4"},
- {"video/x-xvid", "MPEG4"}, {"video/x-3ivx", "MPEG4"},
- {"video/x-avs", "AVS"}, {"video/x-avs+", "AVS+"},
- {"video/x-jpeg", "MJPEG"}, {"video/x-av1", "AV1"},
- {"video/x-h264_tz", "H264"},
- {"video/x-h265_tz", "HEVC"}, {"video/mpeg1_tz", "MPEG1"},
- {"video/mpeg2_tz", "MPEG2"}, {"video/mpeg4_tz", "MPEG4"},
- {"video/x-msmpeg_tz", "MPEG4"}, {"video/x-wmv_tz", "WMV"},
- {"video/x-h263_tz", "H263"}, {"video/x-pn-realvideo_tz", "RV"},
- {"video/x-vp8_tz", "VP8"}, {"video/x-vp9_tz", "VP9"},
- {"video/x-divx_tz", "MPEG4"}, {"video/x-xvid_tz", "MPEG4"},
- {"video/x-3ivx_tz", "MPEG4"}, {"video/x-avs_tz", "AVS"},
- {"video/x-avs+_tz", "AVS+"}, {"video/x-jpeg_tz", "MJPEG"},
- {"video/x-av1_tz", "AV1"},
-
- {"audio/mpeg", "MPEG"}, {"audio/x-aac", "AAC"},
- {"audio/x-true-hd", "TrueHD"}, {"audio/x-ac3", "AC3"},
- {"audio/x-eac3", "E-AC3"}, {"audio/ac3", "AC3"},
- {"audio/x-ac4", "AC4"}, {"audio/x-adpcm", "ADPCM"},
- {"audio/x-wma", "WMA"}, {"audio/x-vorbis", "Vorbis"},
- {"audio/x-gst-fourcc-mha1", "MPEG-H"},{"audio/x-pn-realaudio", "G2Cook"},
- {"audio/x-gst-fourcc-mhm1", "MPEG-H"},{"audio/x-opus", "OPUS"},
- {"audio/x-alaw", "ALAW"}, {"audio/x-mulaw", "MULAW"},
- {"audio/mpeg_tz", "MPEG"}, {"audio/x-aac_tz", "AAC"},
- {"audio/x-ac3_tz", "AC3"}, {"audio/x-eac3_tz", "E-AC3"},
- {"audio/ac3_tz", "AC3"}, {"audio/x-ac4_tz", "AC4"},
- {"audio/x-adpcm_tz", "ADPCM"}, {"audio/x-wma_tz", "WMA"},
- {"audio/x-vorbis_tz", "Vorbis"},{"audio/x-pn-realaudio_tz", "G2Cook"},
- {"audio/x-gst-fourcc-mha1_tz", "MPEG-H"},{"audio/x-raw_tz", "PCM"},
- {"audio/x-gst-fourcc-mhm1_tz", "MPEG-H"},{"audio/x-opus_tz", "OPUS"},
- {"audio/x-alaw_tz", "ALAW"}, {"audio/x-mulaw_tz", "MULAW"},
-};
-// clang-format on
-
-const std::map<ResourceCategory, rm_rsc_category_e> TypeToCategoryConverter = {
- {ResourceCategory::kVideoDecoder, RM_CATEGORY_VIDEO_DECODER},
- {ResourceCategory::kVideoDecoderSub, RM_CATEGORY_VIDEO_DECODER_SUB},
- {ResourceCategory::kVideoRenderer, RM_CATEGORY_SCALER},
- {ResourceCategory::kVideoRendererSub, RM_CATEGORY_SCALER_SUB},
- {ResourceCategory::kVideoRendererSub2, RM_CATEGORY_SCALER_SUB2},
- {ResourceCategory::kVideoRendererSub3, RM_CATEGORY_SCALER_SUB3},
- {ResourceCategory::kAudioDecoder, RM_CATEGORY_AUDIO_DECODER},
- {ResourceCategory::kAudioDecoderSub, RM_CATEGORY_AUDIO_DECODER_SUB},
- {ResourceCategory::kAudioRenderer, RM_CATEGORY_AUDIO_MAIN_OUT},
- {ResourceCategory::kAudioRendererSub, RM_CATEGORY_AUDIO_SUB_OUT}};
-
-const std::map<ResourceCategory, rm_rsc_category_e>
- MultiviewTypeToCategoryConverter = {
- {ResourceCategory::kVideoDecoder, RM_CATEGORY_VIDEO_DECODER},
- {ResourceCategory::kVideoDecoderSub, RM_CATEGORY_VIDEO_DECODER},
- {ResourceCategory::kVideoRenderer, RM_CATEGORY_SCALER},
- {ResourceCategory::kVideoRendererSub, RM_CATEGORY_SCALER},
- {ResourceCategory::kVideoRendererSub2, RM_CATEGORY_SCALER},
- {ResourceCategory::kVideoRendererSub3, RM_CATEGORY_SCALER},
- {ResourceCategory::kAudioDecoder, RM_CATEGORY_AUDIO_DECODER},
- {ResourceCategory::kAudioDecoderSub, RM_CATEGORY_AUDIO_DECODER},
- {ResourceCategory::kAudioRenderer, RM_CATEGORY_AUDIO_MAIN_OUT},
- {ResourceCategory::kAudioRendererSub, RM_CATEGORY_AUDIO_MAIN_OUT}};
-
-const std::map<RscAllocPolicy, rm_requests_resource_state_e>
- TypeToResourceStateConverter = {
- {RscAllocPolicy::kRscAllocExclusive, RM_STATE_EXCLUSIVE},
- {RscAllocPolicy::kRscAllocConditional, RM_STATE_EXCLUSIVE_CONDITIONAL}};
-
-const std::string GetVideoCodecName(const ResourceProperty& property) {
- try {
- std::string mime_type = property.track.mimetype;
- const std::string video_mpeg = "video/mpeg";
- if (mime_type.find(video_mpeg) != std::string::npos)
- mime_type.insert(video_mpeg.size(),
- std::to_string(property.track.version));
- std::string codec_name = MimeTypetoCodecNameConverter.at(mime_type);
- if (property.is_vr360) {
- codec_name.append("_VR360");
- }
- return codec_name;
- } catch (const std::out_of_range& oor) {
- TRACKRENDERER_ERROR(" Unknown mimetype [%s] ",
- property.track.mimetype.c_str());
- return "";
- }
-}
-
-const std::string GetAudioCodecName(const ResourceProperty& property) {
- try {
- std::string mime_type = property.track.mimetype;
- std::string codec_name = MimeTypetoCodecNameConverter.at(mime_type);
- if (property.track.version > 1) {
- codec_name = "AAC";
- // TODO: Need to check "stream-format" info according to mmplayer logic.
- // codec_name should be changed to "HE-AAC" if "stream-format" is "loas".
- }
- return codec_name;
- } catch (const std::out_of_range& oor) {
- TRACKRENDERER_ERROR(" Unknown mimetype [%s] ",
- property.track.mimetype.c_str());
- return "";
- }
-}
-
-double GetFramerate(const int& framerate_num, const int& framerate_den) {
- int framerate = 0;
- if (framerate_num > 0 && framerate_den > 0) {
- framerate = framerate_num / framerate_den;
- } else {
- framerate = kMaxFrameRate;
- return framerate;
- }
-
- framerate = std::min(framerate, kMaxFrameRate);
- return framerate;
-}
-
-int GetWidth(const Track& trackinfo) {
- return trackinfo.maxwidth ? trackinfo.maxwidth : trackinfo.width;
- // TODO(euna7.ko) should i check if value is 0 ?
- // mm get the value from caps. if value is 0, mm set the valeu to HD
- // resolution.
-}
-
-int GetHeight(const Track& trackinfo) {
- return trackinfo.maxheight ? trackinfo.maxheight : trackinfo.height;
-}
-
-inline bool OverFHD(const int width, const int height) {
- return (width > kMaxFhdWidth || height > kMaxFhdHeight) ? true : false;
-}
-
-int GetExplicitDecoderOption(const ResourceProperty& property) {
- constexpr int kAuto = 0;
- if (property.is_multiview) return kAuto;
- if (property.category == ResourceCategory::kVideoDecoder ||
- property.category == ResourceCategory::kAudioDecoder)
- return RM_DEVICE_OPT_MAIN;
- else if (property.category == ResourceCategory::kVideoDecoderSub ||
- property.category == ResourceCategory::kAudioDecoderSub)
- return RM_DEVICE_OPT_SUB;
-
- return kAuto;
-}
-
-int GetVideoDecCategoryOption(const ResourceProperty& property) {
- int category_option = RM_CATEGORY_NONE;
- int width = internal::GetWidth(property.track);
- int height = internal::GetHeight(property.track);
-
- ri_video_category_option_request_s opt;
- memset(&opt, 0, sizeof(ri_video_category_option_request_s));
- std::string codecname = GetVideoCodecName(property);
- if (codecname.empty()) return RI_ERROR;
- opt.codec_name = codecname.c_str();
- opt.color_depth = kDefaultColorDepth;
- opt.h_size = width;
- opt.v_size = height;
- opt.framerate = (int)GetFramerate(property.track.framerate_num,
- property.track.framerate_den);
- opt.sampling_format = kDefaultSamplingFormat;
- if (property.is_ndecoding) {
- category_option = (ri_get_n_decoder_category_id(&opt));
- TRACKRENDERER_INFO(
- " request n decoder codec_name %s, with : %d, height : %d category "
- "option %d",
- opt.codec_name, opt.h_size, opt.v_size, category_option);
- } else {
- category_option = ri_get_capable_video_category_id(&opt);
- }
- if (OverFHD(width, height) || property.is_ndecoding) return category_option;
- int explicit_device = GetExplicitDecoderOption(property);
- category_option |= explicit_device;
- return category_option;
-}
-
-// LCOV_EXCL_START
-int GetVideoJpegDecCategoryOption(const ResourceProperty& property) {
- std::string codecname = GetVideoCodecName(property);
- if (codecname.empty()) return RI_ERROR;
- int width = internal::GetWidth(property.track);
- int height = internal::GetHeight(property.track);
- int category_option = ri_get_jpeg_category_id(codecname.c_str(), width);
- if (OverFHD(width, height)) return category_option;
-
- int explicit_device = GetExplicitDecoderOption(property);
- category_option |= explicit_device;
- return category_option;
-}
-// LCOV_EXCL_STOP
-
-int GetAudioDecCategoryOption(const ResourceProperty& property) {
- ri_audio_category_option_request_s opt;
- memset(&opt, 0, sizeof(ri_audio_category_option_request_s));
- std::string codecname = GetAudioCodecName(property);
- if (codecname.empty()) return RI_ERROR;
- opt.codec_name = codecname.c_str();
- if (property.is_dual_sound) opt.mixing_mode = RI_MIXING_MODE_MULTIVIEW;
-
- int explicit_device = GetExplicitDecoderOption(property);
- int category_option =
- (ri_get_capable_audio_category_id(&opt) | explicit_device);
- return category_option;
-}
-
-int GetScalerCategoryOption(const ResourceProperty& property) {
- constexpr int kAutoScaler = RM_CATEGORY_SCALER;
- int explicit_device = internal::TypeToCategoryConverter.at(property.category);
- int category_option = property.is_multiview ? kAutoScaler : explicit_device;
- return category_option;
-}
-
-int GetAudioOutCategoryOption(const ResourceProperty& property) {
- constexpr int kAutoAudioOut = RM_CATEGORY_AUDIO_MAIN_OUT;
- int explicit_device = internal::TypeToCategoryConverter.at(property.category);
- int category_option = property.is_multiview ? kAutoAudioOut : explicit_device;
- return category_option;
-}
-
-rm_rsc_category_e GetCategoryID(const ResourceProperty& property) {
- rm_rsc_category_e category_id;
- if (property.is_multiview)
- category_id =
- internal::MultiviewTypeToCategoryConverter.at(property.category);
- else
- category_id = internal::TypeToCategoryConverter.at(property.category);
-
- if (property.track.type == kTrackTypeVideo) {
- if (GetVideoCodecName(property) == "MJPEG") {
- return RM_CATEGORY_MJPEG_DECODER;
- }
- }
- return category_id;
-}
-
-bool TryAlloc(ResourceManagerHandle rmhandle, const rm_category_request_s& req,
- rm_device_return_s* devices) {
- int try_count = 5;
- bool ret = false;
- while (try_count--) {
- int rm_ret = rm_allocate_resources(rmhandle, &req, devices);
- if (rm_ret == RM_ERROR) {
- TRACKRENDERER_ERROR("rm_allocate_resources fail[RM_ERROR]");
- break;
- } else if (rm_ret == RM_OK) {
- ret = true;
- break;
- }
- TRACKRENDERER_ERROR("rm_allocate_resources failed rm_ret[%d]", rm_ret);
- TRACKRENDERER_ERROR("retry_count[%d]", try_count);
- std::this_thread::sleep_for(std::chrono::milliseconds(15));
- }
- if (devices->device_id[0] == 0 || devices->omx_comp_name[0] == nullptr) {
- TRACKRENDERER_ERROR("device id or comp name error");
- ret = false;
- }
- return ret;
-}
-
-bool NeedSwDecoderResource(const ResourceProperty& property) {
- if (property.category != ResourceCategory::kVideoDecoder &&
- property.category != ResourceCategory::kVideoDecoderSub &&
- property.category != ResourceCategory::kAudioDecoder &&
- property.category != ResourceCategory::kAudioDecoderSub)
- return false;
- if (property.use_sw) return true;
- return false;
-}
-
-/*
- * ResourceManager handle will be saved in rsc_list after
- * ResourceManager created which will be removed before
- * the handle released in ~ResourceManager(). rsc_lock is to
- * protect that ResourceManager handle is valid if resource
- * conflict happens before trackrenderer handle released.
- */
-static std::mutex rsc_lock;
-static std::list<ResourceManager*> rsc_list;
-
-void AddRMHandle(ResourceManager* handle) {
- TRACKRENDERER_INFO("Resource manager handle[%p]", handle);
- std::lock_guard<std::mutex> lock(rsc_lock);
- rsc_list.push_back(handle);
-}
-
-void RemoveRMHandle(ResourceManager* handle) {
- TRACKRENDERER_INFO("Resource manager handle[%p]", handle);
- std::lock_guard<std::mutex> lock(rsc_lock);
- auto iter = find(rsc_list.begin(), rsc_list.end(), handle);
- if (iter != rsc_list.end()) {
- rsc_list.erase(iter);
- } else {
- TRACKRENDERER_ERROR("Invalid handle[%p]", handle);
- }
-}
-
-using CategoryOption = std::function<int(const ResourceProperty& property)>;
-static std::unordered_map<rm_rsc_category_e, CategoryOption> CategoryOptionMap =
- {{RM_CATEGORY_VIDEO_DECODER, internal::GetVideoDecCategoryOption},
- {RM_CATEGORY_VIDEO_DECODER_SUB, internal::GetVideoDecCategoryOption},
- {RM_CATEGORY_MJPEG_DECODER, internal::GetVideoJpegDecCategoryOption},
- {RM_CATEGORY_SCALER, internal::GetScalerCategoryOption},
- {RM_CATEGORY_SCALER_SUB, internal::GetScalerCategoryOption},
- {RM_CATEGORY_SCALER_SUB2, internal::GetScalerCategoryOption},
- {RM_CATEGORY_SCALER_SUB3, internal::GetScalerCategoryOption},
- {RM_CATEGORY_AUDIO_DECODER, internal::GetAudioDecCategoryOption},
- {RM_CATEGORY_AUDIO_DECODER_SUB, internal::GetAudioDecCategoryOption},
- {RM_CATEGORY_AUDIO_MAIN_OUT, internal::GetAudioOutCategoryOption},
- {RM_CATEGORY_AUDIO_SUB_OUT, internal::GetAudioOutCategoryOption}};
+const std::map<ResourceCategory, mm_resource_manager_res_type_e> TypeToCategoryConverter = {
+ {ResourceCategory::kVideoDecoder, MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER},
+ {ResourceCategory::kVideoRenderer, MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY}};
} // namespace internal
: resourceconflict_listener_(listener) {
assert(listener && "listener is nullptr!!");
- internal::AddRMHandle(this);
- // TODO(js4716.chun) :
- // Add Exception - Assert
- // rm_register(&handle_, ResourceConflictCallback , ...);
- int ret = rm_register((rm_resource_cb)ResourceConflictCallback_, (void*)this,
- &resourcemanager_handle_, NULL);
- assert(ret == RM_OK && "rm_register() is failed");
- TRACKRENDERER_INFO_P(resourceconflict_listener_,
- "resource manager handle = %d, Listener = %p, this = %p",
- resourcemanager_handle_, listener, this);
+ int ret = mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
+ (mm_resource_manager_release_cb)ResourceConflictCallback_,
+ (void*)this, &resourcemanager_handle_);
+ assert(ret == MM_RESOURCE_MANAGER_ERROR_NONE && "rm creation is failed");
+
+ TRACKRENDERER_INFO("resource manager Listener = %p", listener);
}
ResourceManager::~ResourceManager() {
- if (resourcemanager_handle_ != -1) {
- int ret = rm_unregister(resourcemanager_handle_);
- assert(ret == RM_OK && "rm_unregister() is failed");
- TRACKRENDERER_ERROR_P(resourceconflict_listener_,
- "rm_unregister() was done");
- }
-
- internal::RemoveRMHandle(this);
+ int ret = mm_resource_manager_destroy(resourcemanager_handle_);
+ assert(ret == MM_RESOURCE_MANAGER_ERROR_NONE && "rm destroy is failed");
+ TRACKRENDERER_ERROR("rm destroy() was done");
}
-// LCOV_EXCL_START
-rm_cb_result ResourceManager::ResourceConflictCallback_(
- ResourceManagerHandle rmhandle, rm_callback_type eventtype,
- rm_device_request_s* info, void* userdata) {
- TRACKRENDERER_DEBUG(
- "ResourceManagerHandle[%d], cb_type[%d], conflicted num[%d], "
- "device_id[%d]",
- rmhandle, eventtype, info->request_num, info->device_id[0]);
-
+int ResourceManager::ResourceConflictCallback_(
+ ResourceManagerHandle rmhandle, ResourceHandle res, void *userdata)
+{
+ TRACKRENDERER_ENTER;
ResourceManager* resourcemanager = static_cast<ResourceManager*>(userdata);
- /* Do not access non-static variables except callback input parameters
- before checking whether ResourceManager handle is valid.*/
- std::lock_guard<std::mutex> lock(internal::rsc_lock);
- auto iter = find(internal::rsc_list.begin(), internal::rsc_list.end(),
- resourcemanager);
- if (iter == internal::rsc_list.end()) {
- TRACKRENDERER_WARN("ResourceManager[%p] is released", resourcemanager);
- return RM_CB_RESULT_OK;
- }
{
- std::lock_guard<std::mutex> lock2(resourcemanager->control_lock_);
+ std::lock_guard<std::mutex> lock(resourcemanager->control_lock_);
if (resourcemanager->resourcelist_.empty()) {
- TRACKRENDERER_ERROR_P(resourcemanager->resourceconflict_listener_,
- "resourcelist is empty! return.");
- return RM_CB_RESULT_OK;
+ TRACKRENDERER_ERROR("resourcelist is empty! return.");
+ return true;
}
}
if (!resourcemanager->resourceconflict_listener_) {
TRACKRENDERER_ERROR("confilict listener is nullptr. ERROR!");
assert(0 && "resourceconflict_listener_ is nullptr");
- return RM_CB_RESULT_ERROR;
+ return true;
}
resourcemanager->resourceconflict_listener_->OnResourceConflicted();
- TRACKRENDERER_LEAVE_P(resourcemanager->resourceconflict_listener_);
- return RM_CB_RESULT_OK;
-}
-// LCOV_EXCL_STOP
-
-void ResourceManager::SetAppId(const std::string& appid) {
- if (appid.empty()) return;
- rm_set_app_id(resourcemanager_handle_, const_cast<char*>(appid.c_str()));
- app_id_ = appid;
-}
+ /* default player > OnResourceConflicted > trackrenderer_->Stop() */
+ /* es player > OnResourceConflicted > trackrenderer_->Stop */
-bool ResourceManager::NeedPulseResource(const ResourceProperty& property) {
- if (property.category != ResourceCategory::kAudioRenderer || !property.use_sw)
- return false;
- rm_resource_list_h list;
-
- BOOST_SCOPE_EXIT(&list) { rm_free_resource_list(list); }
- BOOST_SCOPE_EXIT_END
-
- rm_get_resource_list(RM_CATEGORY_AUDIO_MAIN_OUT, &list);
- rm_resource_h rsc = rm_resource_list_get_first(list);
- while (rsc) {
- if (rm_resource_get_state(rsc) != RM_RSC_STATE_FREE) {
- bool is_main_device = ri_is_main_device(rm_resource_get_id(rsc));
- if (is_main_device) {
- const char* app_id = rm_resource_get_app_id(rsc);
- if (!strcmp(app_id_.c_str(), app_id)) {
- TRACKRENDERER_INFO_P(
- resourceconflict_listener_,
- "need pulsesink current app id [%s] allocated app id[%s]",
- app_id_.c_str(), app_id);
- return true;
- }
- }
- }
- rsc = rm_resource_list_get_next(list);
- }
- return false;
-}
-
-bool ResourceManager::AllocPulseResource_(const ResourceProperty& property) {
- resourcelist_.emplace_back(property, kPulseSinkComponentName);
+ TRACKRENDERER_LEAVE;
return true;
}
-bool ResourceManager::AllocSwDecoderResource_(
- const ResourceProperty& property) {
- resourcelist_.emplace_back(property, kSwDecoderComponentName);
- return true;
-}
-bool ResourceManager::AllocHWResource_(const ResourceProperty& property) {
- rm_category_request_s req;
- memset(&req, 0, sizeof(rm_category_request_s));
- AllocatedState avail_state = MakeCategoryRequest_(property, &req);
- TRACKRENDERER_ERROR_P(resourceconflict_listener_, "available state[%d]",
- static_cast<int>(avail_state));
-
- if (avail_state == AllocatedState::kFailed) return false;
- if (avail_state == AllocatedState::kSkipped) {
- resourcelist_.emplace_back(property, avail_state);
- return true;
- }
- return TryAllocHWResource_(property, req);
-}
-
-bool ResourceManager::TryAllocHWResource_(const ResourceProperty& property,
- const rm_category_request_s& req) {
- rm_device_return_s devices;
- memset(&devices, 0, sizeof(rm_device_return_s));
- if (internal::TryAlloc(resourcemanager_handle_, req, &devices) == false) {
- TRACKRENDERER_ERROR_P(resourceconflict_listener_,
- "rm_allocate_resources FAIL.");
- return false;
- }
+bool ResourceManager::Acquire(const std::list<ResourceProperty>& properties) {
+ TRACKRENDERER_ENTER;
+ for (const auto& property : properties) {
+ ResourceHandle res = nullptr;
+ int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
- TRACKRENDERER_INFO_P(resourceconflict_listener_,
- "resource Type[%d], device id[%d], comp_name[%s]",
- static_cast<int>(property.category),
- devices.device_id[0], devices.omx_comp_name[0]);
+ TRACKRENDERER_INFO("resource Type[%d]", static_cast<int>(property.category));
- resourcelist_.emplace_back(property, devices.device_id[0],
- devices.omx_comp_name[0]);
+ /* FIXME_RM : can get res vol size based on the property.track */
+ rm_ret = mm_resource_manager_mark_for_acquire(resourcemanager_handle_,
+ internal::TypeToCategoryConverter.at(property.category),
+ MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &res);
+ if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ TRACKRENDERER_ERROR("failed to mark resource for acquire, ret(0x%x)", rm_ret);
+ return false;
+ }
- if (devices.device_node[0]) {
- free(devices.device_node[0]);
- }
- if (devices.omx_comp_name[0]) {
- free(devices.omx_comp_name[0]);
+ rm_ret = mm_resource_manager_commit(resourcemanager_handle_);
+ if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ TRACKRENDERER_ERROR("failed to commit of resource, ret(0x%x)", rm_ret);
+ return false;
+ }
+ resourcelist_.emplace_back(property, res);
+ TRACKRENDERER_INFO("resource acquired");
}
- return true;
-}
-int ResourceManager::GetCategoryOption_(const rm_rsc_category_e& category_id,
- const ResourceProperty& property) {
- auto& mapper = internal::CategoryOptionMap.at(category_id);
- int capable_category = mapper(property);
- TRACKRENDERER_INFO_P(resourceconflict_listener_,
- "capable_category_option : %d", capable_category);
- int category_option = rc_get_capable_category_id(
- resourcemanager_handle_, app_id_.c_str(), capable_category);
- TRACKRENDERER_INFO_P(resourceconflict_listener_, "capable_category_id : %d",
- category_option);
- return category_option;
+ TRACKRENDERER_LEAVE;
+ return true;
}
-AllocatedState ResourceManager::MakeCategoryRequest_(
- const ResourceProperty& property, rm_category_request_s* req) {
- req->request_num = 1;
- req->state[0] =
- internal::TypeToResourceStateConverter.at(property.rsc_alloc_policy);
- req->category_id[0] = internal::GetCategoryID(property);
- req->category_option[0] = GetCategoryOption_(req->category_id[0], property);
- if (req->category_option[0] == RI_ERROR)
- return AllocatedState::kFailed;
- else if (req->category_option[0] == RI_CATEGORY_NOT_PERMITTED)
- return AllocatedState::kSkipped;
-
- return AllocatedState::kSuccess;
-}
+bool ResourceManager::Release() {
+ int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
-bool ResourceManager::Alloc_(const ResourceProperty& property) {
- if (internal::NeedSwDecoderResource(property)) {
- return AllocSwDecoderResource_(property);
- } else if (NeedPulseResource(property)) {
- return AllocPulseResource_(property);
- } else {
- return AllocHWResource_(property);
- }
-}
+ TRACKRENDERER_ENTER;
+ if (resourcelist_.empty() || resourcelist_.size() == 0) return true;
-bool ResourceManager::Alloc(const std::list<ResourceProperty>& properties) {
- for (const auto& property : properties) {
- TRACKRENDERER_INFO_P(resourceconflict_listener_,
- "Resource Type[%d], use_sw[%d]",
- static_cast<int>(property.category), property.use_sw);
- if (Alloc_(property) == false) return false;
+ rm_ret = mm_resource_manager_mark_all_for_release(resourcemanager_handle_);
+ if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ TRACKRENDERER_ERROR("failed to mark resource for release, ret(0x%x)", rm_ret);
+ return false;
}
- return true;
-}
-
-bool ResourceManager::Dealloc() {
- TRACKRENDERER_ENTER_P(resourceconflict_listener_);
-
- if (resourcelist_.empty()) return true;
- rm_device_request_s devices;
- memset(&devices, 0, sizeof(rm_device_request_s));
-
- if (resourcelist_.size() == 0) return true; // There is no resource.
-
- unsigned int device_num = 0;
- std::for_each(resourcelist_.begin(), resourcelist_.end(),
- [&devices, &device_num](const Resource& resource) {
- if (resource.GetDeviceId() != 0) {
- devices.device_id[device_num++] = resource.GetDeviceId();
- }
- });
- if (device_num > 0) {
- devices.request_num = device_num;
- int rm_err = rm_deallocate_resources(resourcemanager_handle_, &devices);
- if (rm_err != RM_OK) {
- TRACKRENDERER_ERROR_P(resourceconflict_listener_,
- "rm_deallocate_resources failed, rm_err[%d]",
- rm_err);
- return false;
- }
- } else {
- TRACKRENDERER_INFO_P(resourceconflict_listener_,
- "therer are no resource to dealloc");
- return true;
+ rm_ret = mm_resource_manager_commit(resourcemanager_handle_);
+ if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ TRACKRENDERER_ERROR("failed to commit of resource, ret(0x%x)", rm_ret);
+ return false;
}
{
std::lock_guard<std::mutex> lock(control_lock_);
resourcelist_.clear();
}
- TRACKRENDERER_LEAVE_P(resourceconflict_listener_);
+ TRACKRENDERER_LEAVE;
return true;
}
-bool ResourceManager::Dealloc(const ResourceCategory type) {
- TRACKRENDERER_ENTER_P(resourceconflict_listener_);
+bool ResourceManager::Release(const ResourceCategory type) {
+ int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
+
+ TRACKRENDERER_ENTER;
+
if (resourcelist_.empty()) return true;
- rm_device_request_s devices;
- memset(&devices, 0, sizeof(rm_device_request_s));
- devices.request_num = 1;
- auto compare = [type](Resource& item) noexcept -> bool {
+ auto compare = [type](Resource & item) noexcept->bool {
return item.GetResourceCategory() == type;
};
auto target =
// There is no resource.
if (target == resourcelist_.end()) return true;
- if (target->GetDeviceId() == 0) {
- std::lock_guard<std::mutex> lock(control_lock_);
- resourcelist_.erase(target);
- TRACKRENDERER_DEBUG_P(resourceconflict_listener_,
- "resourcelist_.size() = %d", resourcelist_.size());
- return true;
- }
- devices.device_id[0] = target->GetDeviceId();
+ TRACKRENDERER_INFO("resource Type[%d]", (int)type);
+ rm_ret = mm_resource_manager_mark_for_release(resourcemanager_handle_, target->GetResourceHandle());
+ if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ TRACKRENDERER_ERROR("failed to mark resource for release, ret(0x%x)", rm_ret);
+ return false;
+ }
- int rm_err = rm_deallocate_resources(resourcemanager_handle_, &devices);
- if (rm_err != RM_OK) {
- TRACKRENDERER_ERROR_P(resourceconflict_listener_,
- "rm_deallocate_resources failed, rm_err[%d]", rm_err);
- return false;
- }
+ rm_ret = mm_resource_manager_commit(resourcemanager_handle_);
+ if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ TRACKRENDERER_ERROR("failed to commit of resource, ret(0x%x)", rm_ret);
+ return false;
+ }
{
std::lock_guard<std::mutex> lock(control_lock_);
resourcelist_.erase(target);
- TRACKRENDERER_DEBUG_P(resourceconflict_listener_,
- "resourcelist_.size() = %d", resourcelist_.size());
+ TRACKRENDERER_DEBUG("resourcelist_.size() = %zu", resourcelist_.size());
}
- TRACKRENDERER_LEAVE_P(resourceconflict_listener_);
- return true;
-}
-std::string ResourceManager::GetComponentName(const ResourceCategory type) {
- auto compare = [type](const Resource& item) noexcept -> bool {
- return item.GetResourceCategory() == type;
- };
- auto target =
- std::find_if(resourcelist_.begin(), resourcelist_.end(), compare);
- if (target == resourcelist_.end()) return {};
-
- TRACKRENDERER_INFO_P(resourceconflict_listener_, "Comp name : %s",
- (target->GetComponentName()).c_str());
- return target->GetComponentName();
-}
-
-int ResourceManager::GetRawHandle() { return resourcemanager_handle_; }
-
-AllocatedState ResourceManager::GetAllocatedState(const ResourceCategory type) {
- auto compare = [type](const Resource& item) noexcept -> bool {
- return item.GetResourceCategory() == type;
- };
- auto target =
- std::find_if(resourcelist_.begin(), resourcelist_.end(), compare);
- if (target == resourcelist_.end()) return AllocatedState::kFailed;
-
- TRACKRENDERER_INFO_P(resourceconflict_listener_, "Allocated State : %d",
- static_cast<int>(target->GetAllocatedState()));
- return target->GetAllocatedState();
-}
-
-bool ResourceManager::IsMainDevice(const ResourceCategory& type) {
- TRACKRENDERER_ENTER_P(resourceconflict_listener_);
- auto compare = [type](const Resource& item) noexcept -> bool {
- return item.GetResourceCategory() == type;
- };
- auto target =
- std::find_if(resourcelist_.begin(), resourcelist_.end(), compare);
- if (target == resourcelist_.end()) {
- TRACKRENDERER_WARN_P(resourceconflict_listener_,
- "This resource[%d] is not allocated.",
- static_cast<int>(type));
- return true;
- }
-
- int device_id = target->GetDeviceId();
- if (type == ResourceCategory::kVideoRenderer ||
- type == ResourceCategory::kVideoRendererSub ||
- type == ResourceCategory::kVideoRendererSub2 ||
- type == ResourceCategory::kVideoRendererSub3) {
- device_id = rm_find_device_id(device_id);
- }
- bool is_main = ri_is_main_device(device_id);
- TRACKRENDERER_INFO_P(resourceconflict_listener_,
- "This resrouce[%d] is [%s] device",
- static_cast<int>(type), is_main ? "main" : "sub");
- return is_main;
-}
-
-int ResourceManager::GetDeviceId(const ResourceCategory& type) {
- TRACKRENDERER_ENTER_P(resourceconflict_listener_);
- auto compare = [type](const Resource& item) noexcept -> bool {
- return item.GetResourceCategory() == type;
- };
- auto target =
- std::find_if(resourcelist_.begin(), resourcelist_.end(), compare);
- if (target == resourcelist_.end()) {
- TRACKRENDERER_ERROR_P(resourceconflict_listener_,
- "This resource[%d] is not allocated ",
- static_cast<int>(type));
- return -1; // invalid device id
- }
- return target->GetDeviceId();
-}
-
-bool ResourceManager::IsAudioFocused() {
- bool is_audio_focused = rc_is_audio_focused(app_id_.c_str());
- TRACKRENDERER_INFO("is audio focused [%d]", is_audio_focused);
- return is_audio_focused;
+ TRACKRENDERER_LEAVE;
+ return true;
}
} // namespace trackrenderer
+++ /dev/null
-//
-// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#include "trackrenderer/core/screen_saver.h"
-#include "trackrenderer/core/utils/log.h"
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-static int timeout_timer_id_ = 0;
-#define ResetTimeoutValue 30 // timeout second
-
-ScreenSaver::~ScreenSaver() {}
-
-void ScreenSaver::StartTimeout() {
- if (timeout_timer_id_ == 0) {
- int ret = screensaver_reset_timeout();
- TRACKRENDERER_DEBUG("screensaver_reset_timeout start : ret = %d", ret);
- timeout_timer_id_ =
- g_timeout_add_seconds(ResetTimeoutValue, ResetTimeout, NULL);
- TRACKRENDERER_DEBUG("timer_id = %d", timeout_timer_id_);
- }
-}
-
-void ScreenSaver::StopTimeout() {
- if (timeout_timer_id_ != 0) {
- TRACKRENDERER_DEBUG("timer_id = %d", timeout_timer_id_);
- g_source_remove(timeout_timer_id_);
- timeout_timer_id_ = 0;
- }
- TRACKRENDERER_DEBUG("remove screensaver reset timer");
-}
-
-gboolean ScreenSaver::ResetTimeout(gpointer data) {
- int ret = screensaver_reset_timeout();
- TRACKRENDERER_DEBUG("screensaver_reset_timeout resume: ret = %d", ret);
- return true;
-}
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
+++ /dev/null
-//
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#include "trackrenderer/subtitle_attr_parser.h"
-
-#include <algorithm>
-#include <cassert>
-
-#include "gst/ffsubtitle/gstsubattributes.h"
-
-#include "trackrenderer/core/utils/log.h"
-// LCOV_EXCL_START
-namespace plusplayer {
-
-namespace trackrenderer {
-
-namespace internal {
-void AddSubtitleAttribute(std::list<SubtitleAttr>* list,
- const SubtitleAttrType type, const boost::any& value,
- const unsigned int start_pos,
- const unsigned int stop_pos) {
- list->emplace_back(type, start_pos, stop_pos, value, -1);
-}
-
-bool ComparingStartTime(const SubtitleAttr& a, const SubtitleAttr& b) {
- return (a.start_time < b.start_time);
-}
-
-constexpr int kAttrInvalidIntVal = -1;
-constexpr unsigned int kAttrInvalidUintVal =
- std::numeric_limits<unsigned int>::max();
-constexpr float kAttrInvalidFloatVal = 0.0;
-
-void ParseSubtitleRegionAttr(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_ENTER;
- while (attribute) {
- gfloat x_pos = kAttrInvalidIntVal, y_pos = kAttrInvalidFloatVal,
- width = kAttrInvalidFloatVal, height = kAttrInvalidFloatVal;
- attribute = gst_sub_attribute_region_parse(attribute, &x_pos, &y_pos,
- &width, &height);
- TRACKRENDERER_DEBUG(
- "parsed new region attribute: x(%f), y(%f), width(%f), "
- "height(%f)",
- x_pos, y_pos, width, height);
- if (x_pos != kAttrInvalidFloatVal) {
- boost::any value = x_pos;
- internal::AddSubtitleAttribute(attr_list, kSubAttrRegionXPos, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- if (y_pos != kAttrInvalidFloatVal) {
- boost::any value = y_pos;
- internal::AddSubtitleAttribute(attr_list, kSubAttrRegionYPos, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- if (width != kAttrInvalidFloatVal) {
- boost::any value = width;
- internal::AddSubtitleAttribute(attr_list, kSubAttrRegionWidth, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- if (height != kAttrInvalidFloatVal) {
- boost::any value = height;
- internal::AddSubtitleAttribute(attr_list, kSubAttrRegionHeight, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- }
-}
-
-void ParseSubtitleWindowAttr(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_ENTER;
- while (attribute) {
- gfloat x_padding = kAttrInvalidFloatVal, y_padding = kAttrInvalidFloatVal;
- gint l_margin = kAttrInvalidIntVal, r_margin = kAttrInvalidIntVal,
- t_margin = kAttrInvalidIntVal, b_margin = kAttrInvalidIntVal;
- guint bg_color = kAttrInvalidUintVal;
- gfloat opacity = kAttrInvalidFloatVal;
- guint show_bg = kAttrInvalidUintVal;
- attribute = gst_sub_attribute_window_parse(
- attribute, &x_padding, &y_padding, &l_margin, &r_margin, &t_margin,
- &b_margin, &bg_color, &opacity, &show_bg);
- TRACKRENDERER_DEBUG(
- "parsed new window attribute: x_padding(%f), y_padding(%f), "
- "l_margin(%d), r_margin(%d), t_margin(%d), b_margin(%d), "
- "bg_color(%u), opacity(%f), show_bg(%u)",
- x_padding, y_padding, l_margin, r_margin, t_margin, b_margin, bg_color,
- opacity, show_bg);
- if (x_padding != kAttrInvalidFloatVal) {
- boost::any value = x_padding;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWindowXPadding, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- if (y_padding != kAttrInvalidFloatVal) {
- boost::any value = y_padding;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWindowYPadding, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- if (l_margin != kAttrInvalidIntVal) {
- boost::any value = l_margin;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWindowLeftMargin, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- if (r_margin != kAttrInvalidIntVal) {
- boost::any value = r_margin;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWindowRightMargin,
- value, kAttrInvalidUintVal,
- kAttrInvalidUintVal);
- }
- if (t_margin != kAttrInvalidIntVal) {
- boost::any value = t_margin;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWindowTopMargin, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- if (b_margin != kAttrInvalidIntVal) {
- boost::any value = b_margin;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWindowBottomMargin,
- value, kAttrInvalidUintVal,
- kAttrInvalidUintVal);
- }
- if (bg_color != kAttrInvalidUintVal) {
- boost::any value = bg_color;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWindowBgColor, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- if (opacity != kAttrInvalidFloatVal) {
- boost::any value = opacity;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWindowOpacity, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- if (show_bg != kAttrInvalidUintVal) {
- boost::any value = show_bg;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWindowShowBg, value,
- kAttrInvalidUintVal, kAttrInvalidUintVal);
- }
- }
-}
-
-void ParseSubtitleFontAttr(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_DEBUG("Now parse attribute font!");
- while (attribute) {
- GstSubAttributeScope scope;
- guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
- gchar* family = nullptr;
- gfloat size = kAttrInvalidFloatVal;
- gint weight = kAttrInvalidIntVal, style = kAttrInvalidIntVal;
- guint color = kAttrInvalidUintVal, bg_color = kAttrInvalidUintVal;
- gfloat opacity = kAttrInvalidFloatVal, bg_opacity = kAttrInvalidFloatVal;
- guint text_outline_color = kAttrInvalidUintVal,
- text_outline_tn = kAttrInvalidUintVal;
- gint text_outline_br = kAttrInvalidIntVal, v_align = kAttrInvalidIntVal,
- h_align = kAttrInvalidIntVal;
- attribute = gst_sub_attribute_font_parse(
- attribute, &scope, &start_index, &stop_index, &family, &size, &weight,
- &style, &color, &bg_color, &opacity, &bg_opacity, &text_outline_color,
- &text_outline_tn, &text_outline_br, &v_align, &h_align);
- TRACKRENDERER_DEBUG(
- "passed a font attribute: scope(%u), start_index(%u), "
- "stop_index(%u), family(%s), size(%f),"
- "weight(%d), style(%d), color(%u), bg_color(%u), opacity(%f), "
- "bg_opacity(%f), text_outline_color(%u),"
- "text_outline_tn(%u),text_outline_br(%d), v_align(%d), "
- "h_align(%d)",
- scope, start_index, stop_index, family, size, weight, style, color,
- bg_color, opacity, bg_opacity, text_outline_color, text_outline_tn,
- text_outline_br, v_align, h_align);
- if (family != nullptr) {
- boost::any value = std::string(family);
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontFamily, value,
- start_index, stop_index);
- }
- if (size != kAttrInvalidFloatVal) {
- boost::any value = size;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontSize, value,
- start_index, stop_index);
- }
- if (weight != kAttrInvalidIntVal) {
- boost::any value = weight;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontWeight, value,
- start_index, stop_index);
- }
- if (style != kAttrInvalidIntVal) {
- boost::any value = style;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontStyle, value,
- start_index, stop_index);
- }
- if (color != kAttrInvalidUintVal) {
- boost::any value = color;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontColor, value,
- start_index, stop_index);
- }
- if (bg_color != kAttrInvalidUintVal) {
- boost::any value = bg_color;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontBgColor, value,
- start_index, stop_index);
- }
- if (opacity != kAttrInvalidFloatVal) {
- boost::any value = opacity;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontOpacity, value,
- start_index, stop_index);
- }
- if (bg_opacity != kAttrInvalidFloatVal) {
- boost::any value = bg_opacity;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontBgOpacity, value,
- start_index, stop_index);
- }
- if (text_outline_color != kAttrInvalidUintVal) {
- boost::any value = text_outline_color;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontTextOutlineColor,
- value, start_index, stop_index);
- }
- if (text_outline_tn != kAttrInvalidUintVal) {
- boost::any value = text_outline_tn;
- internal::AddSubtitleAttribute(attr_list,
- kSubAttrFontTextOutlineThickness, value,
- start_index, stop_index);
- }
- if (text_outline_br != kAttrInvalidIntVal) {
- boost::any value = text_outline_br;
- internal::AddSubtitleAttribute(attr_list,
- kSubAttrFontTextOutlineBlurRadius, value,
- start_index, stop_index);
- }
- if (v_align != kAttrInvalidIntVal) {
- boost::any value = v_align;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontVerticalAlign,
- value, start_index, stop_index);
- }
- if (h_align != kAttrInvalidIntVal) {
- boost::any value = h_align;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontHorizontalAlign,
- value, start_index, stop_index);
- }
- }
-}
-void ParseSubtitleFontSizeWeightStyleClolr(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_DEBUG("Now parse attribute font shortcut SIZE_WEIGHT_STYLE_COLOR!");
- while (attribute) {
- GstSubAttributeScope scope;
- guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
- gfloat size = kAttrInvalidFloatVal;
- gint weight = kAttrInvalidIntVal, style = kAttrInvalidIntVal;
- guint color = kAttrInvalidUintVal;
- attribute = gst_sub_attribute_font_sc_size_weight_style_color_parse(
- attribute, &scope, &start_index, &stop_index, &size, &weight, &style,
- &color);
- TRACKRENDERER_DEBUG(
- "passed a font attribute: scope(%u), start_index(%u), "
- "stop_index(%u), size(%f),"
- "weight(%d), style(%d), color(%u)",
- scope, start_index, stop_index, size, weight, style, color);
- if (size != kAttrInvalidFloatVal) {
- boost::any value = size;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontSize, value,
- start_index, stop_index);
- }
- if (weight != kAttrInvalidIntVal) {
- boost::any value = weight;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontWeight, value,
- start_index, stop_index);
- }
- if (style != kAttrInvalidIntVal) {
- boost::any value = style;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontStyle, value,
- start_index, stop_index);
- }
- if (color != kAttrInvalidUintVal) {
- boost::any value = color;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontColor, value,
- start_index, stop_index);
- }
- }
-}
-void ParseSubtitleFontColorOpacities(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_DEBUG("Now parse attribute font shortcut SIZE_COLORS_AND_OPACITIES!");
- while (attribute) {
- GstSubAttributeScope scope;
- guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal,
- color = kAttrInvalidUintVal, bg_color = kAttrInvalidUintVal;
- gfloat opacity = kAttrInvalidFloatVal, bg_opacity = kAttrInvalidFloatVal;
- guint text_outline_color = kAttrInvalidUintVal;
- attribute = gst_sub_attribute_font_sc_colors_and_opacities_parse(
- attribute, &scope, &start_index, &stop_index, &color, &bg_color,
- &opacity, &bg_opacity, &text_outline_color);
- TRACKRENDERER_DEBUG(
- "passed a font attribute: scope(%u), start_index(%u), "
- "stop_index(%u),"
- "color(%u), bg_color(%u), opacity(%f), bg_opacity(%f), "
- "text_outline_color(%u)",
- scope, start_index, stop_index, color, bg_color, opacity, bg_opacity,
- text_outline_color);
- if (color != kAttrInvalidUintVal) {
- boost::any value = color;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontColor, value,
- start_index, stop_index);
- }
- if (bg_color != kAttrInvalidUintVal) {
- boost::any value = bg_color;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontBgColor, value,
- start_index, stop_index);
- }
- if (opacity != kAttrInvalidFloatVal) {
- boost::any value = opacity;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontOpacity, value,
- start_index, stop_index);
- }
- if (bg_opacity != kAttrInvalidFloatVal) {
- boost::any value = bg_opacity;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontBgOpacity, value,
- start_index, stop_index);
- }
- if (text_outline_color != kAttrInvalidUintVal) {
- boost::any value = text_outline_color;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontTextOutlineColor,
- value, start_index, stop_index);
- }
- }
-}
-void ParseSubtitleFontSize(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_DEBUG("Now parse attribute font shortcut SIZE!");
- while (attribute) {
- guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
- gfloat size = kAttrInvalidFloatVal;
- attribute = gst_sub_attribute_font_sc_size_parse(attribute, &start_index,
- &stop_index, &size);
- TRACKRENDERER_DEBUG(
- "passed a font attribute: start_index(%u), stop_index(%u), "
- "size(%f)",
- start_index, stop_index, size);
- if (size != kAttrInvalidFloatVal) {
- boost::any value = size;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontSize, value,
- start_index, stop_index);
- }
- }
-}
-void ParseSubtitleFontWeight(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_DEBUG("Now parse attribute font shortcut WEIGHT!");
- while (attribute) {
- guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
- gint weight = kAttrInvalidIntVal;
- attribute = gst_sub_attribute_font_sc_weight_parse(attribute, &start_index,
- &stop_index, &weight);
- TRACKRENDERER_DEBUG(
- "passed a font attribute: start_index(%u), stop_index(%u), "
- "weight(%d)",
- start_index, stop_index, weight);
- if (weight != kAttrInvalidIntVal) {
- boost::any value = weight;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontWeight, value,
- start_index, stop_index);
- }
- }
-}
-void ParseSubtitleFontStyle(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_DEBUG("Now parse attribute font shortcut STYLE!");
- while (attribute) {
- guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
- gint style = kAttrInvalidIntVal;
- attribute = gst_sub_attribute_font_sc_style_parse(attribute, &start_index,
- &stop_index, &style);
- TRACKRENDERER_DEBUG(
- "passed a font attribute: start_index(%u), stop_index(%u), "
- "style(%d)",
- start_index, stop_index, style);
- if (style != kAttrInvalidIntVal) {
- boost::any value = style;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontStyle, value,
- start_index, stop_index);
- }
- }
-}
-void ParseSubtitleFontColor(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_DEBUG("Now parse attribute font shortcut COLOR!");
- while (attribute) {
- guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
- guint color = kAttrInvalidUintVal;
- attribute = gst_sub_attribute_font_sc_color_parse(attribute, &start_index,
- &stop_index, &color);
- TRACKRENDERER_DEBUG(
- "passed a font attribute: start_index(%u), stop_index(%u), "
- "color(%u)",
- start_index, stop_index, color);
- if (color != kAttrInvalidUintVal) {
- boost::any value = color;
- internal::AddSubtitleAttribute(attr_list, kSubAttrFontColor, value,
- start_index, stop_index);
- }
- }
-}
-void ParseSubtitleRaw(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_DEBUG("Now parse attribute raw!");
- while (attribute) {
- guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
- gchar* raw_subtitle = nullptr;
- attribute = gst_sub_attribute_raw_data(attribute, &raw_subtitle);
- TRACKRENDERER_DEBUG("passed a raw attribute: raw_subtitle(%s)", raw_subtitle);
- if (raw_subtitle != nullptr) {
- boost::any value = std::string(raw_subtitle);
- internal::AddSubtitleAttribute(attr_list, kSubAttrRawSubtitle, value,
- start_index, stop_index);
- }
- }
-}
-void ParseSubtitleWebvttCue(GstStructure* attribute,
- std::list<SubtitleAttr>* attr_list) {
- TRACKRENDERER_DEBUG("Now parse attribute of webvtt cue!");
- while (attribute) {
- guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
- gint line_num = kAttrInvalidIntVal, line_align = kAttrInvalidIntVal,
- pos_align = kAttrInvalidIntVal, align = kAttrInvalidIntVal,
- vertical = kAttrInvalidIntVal;
- gfloat line = kAttrInvalidFloatVal, size = kAttrInvalidFloatVal,
- position = kAttrInvalidFloatVal;
- attribute = gst_sub_attribute_webvttcue_parse(
- attribute, &line, &line_num, &line_align, &align, &size, &position,
- &pos_align, &vertical);
- TRACKRENDERER_DEBUG(
- "passed webvttcue attributes: line(%f), line_num(%d), line_align(%d), "
- "align(%d), size(%f), position(%f), pos_align(%d), vertical(%d)",
- line, line_num, line_align, align, size, position, pos_align, vertical);
- if (line != kAttrInvalidFloatVal) {
- boost::any value = line;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueLine, value,
- start_index, stop_index);
- }
- if (line_num != kAttrInvalidIntVal) {
- boost::any value = line_num;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueLineNum, value,
- start_index, stop_index);
- }
- if (line_align != kAttrInvalidIntVal) {
- boost::any value = line_align;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueLineAlign,
- value, start_index, stop_index);
- }
- if (align != kAttrInvalidIntVal) {
- boost::any value = align;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueAlign, value,
- start_index, stop_index);
- }
- if (size != kAttrInvalidFloatVal) {
- boost::any value = size;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueSize, value,
- start_index, stop_index);
- }
- if (position != kAttrInvalidFloatVal) {
- boost::any value = position;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCuePosition,
- value, start_index, stop_index);
- }
- if (pos_align != kAttrInvalidIntVal) {
- boost::any value = pos_align;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCuePositionAlign,
- value, start_index, stop_index);
- }
- if (vertical != kAttrInvalidIntVal) {
- boost::any value = vertical;
- internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueVertical,
- value, start_index, stop_index);
- }
- }
-}
-
-} // namespace internal
-
-SubtitleAttrListPtr SubtitleAttrParser::Parse() {
- SubtitleAttrListPtr attr_list{new SubtitleAttrList};
- for (int attr_type = GST_SUB_ATTRI_TYPE_REGION;
- attr_type < GST_SUB_ATTRI_TYPE_UNKNOWN; ++attr_type) {
- const gchar* type_name =
- gst_sub_attribute_type_to_name((GstSubAttributeType)attr_type);
- GQuark attri_quark =
- gst_sub_attribute_type_to_quark((GstSubAttributeType)attr_type);
- if (!attri_quark) {
- TRACKRENDERER_DEBUG("We don't have quark of this attribute type(%s)!", type_name);
- continue;
- }
-
- GstStructure* attribute = GST_STRUCTURE_CAST(
- gst_mini_object_get_qdata(GST_MINI_OBJECT(gstbuf_), attri_quark));
-
- if (!attribute) continue;
- TRACKRENDERER_DEBUG("attribute type(%s) from gstbuffer!", type_name);
-
- switch (attr_type) {
- case GST_SUB_ATTRI_TYPE_REGION:
- internal::ParseSubtitleRegionAttr(attribute, attr_list.get());
- break;
- case GST_SUB_ATTRI_TYPE_WINDOW:
- internal::ParseSubtitleWindowAttr(attribute, attr_list.get());
- break;
- case GST_SUB_ATTRI_TYPE_FONT:
- internal::ParseSubtitleFontAttr(attribute, attr_list.get());
- break;
- case GST_SUB_ATTRI_TYPE_FONT_SC_SIZE_WEIGHT_STYLE_COLOR:
- internal::ParseSubtitleFontSizeWeightStyleClolr(attribute,
- attr_list.get());
- break;
- case GST_SUB_ATTRI_TYPE_FONT_SC_COLORS_AND_OPACITIES:
- internal::ParseSubtitleFontColorOpacities(attribute, attr_list.get());
- break;
- case GST_SUB_ATTRI_TYPE_FONT_SC_SIZE:
- internal::ParseSubtitleFontSize(attribute, attr_list.get());
- break;
- case GST_SUB_ATTRI_TYPE_FONT_SC_WEIGHT:
- internal::ParseSubtitleFontWeight(attribute, attr_list.get());
- break;
- case GST_SUB_ATTRI_TYPE_FONT_SC_STYLE:
- internal::ParseSubtitleFontStyle(attribute, attr_list.get());
- break;
- case GST_SUB_ATTRI_TYPE_FONT_SC_COLOR:
- internal::ParseSubtitleFontColor(attribute, attr_list.get());
- break;
- case GST_SUB_ATTRI_TYPE_RAW:
- internal::ParseSubtitleRaw(attribute, attr_list.get());
- break;
- case GST_SUB_ATTRI_TYPE_WEBVTT_CUE:
- internal::ParseSubtitleWebvttCue(attribute, attr_list.get());
- break;
- default:
- TRACKRENDERER_ERROR("UNKNOWN ATTR TYPE");
- return nullptr;
- }
- }
-
- (attr_list.get())->sort(internal::ComparingStartTime);
- boost::any value = 0;
- GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
- duration = GST_TIME_AS_MSECONDS(GST_BUFFER_DURATION(gstbuf_));
- timestamp = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(gstbuf_));
- TRACKRENDERER_DEBUG("pts[%llu] duration[%llu]", timestamp, duration);
- internal::AddSubtitleAttribute(attr_list.get(), kSubAttrTimestamp, value,
- timestamp, timestamp + duration);
-
- return attr_list;
-}
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
-// LCOV_EXCL_STOP
+++ /dev/null
-// LCOV_EXCL_START
-#include "trackrenderer_capi/track_capi.h"
-
-#include <cstring>
-#include <memory>
-
-#include "trackrenderer/core/track.h"
-#include "trackrenderer/core/track_util.h"
-#include "trackrenderer/trackrenderer_capi_utils.h"
-
-namespace tr = plusplayer::trackrenderer;
-
-namespace {
-tr::Track* cast_(TrackRendererTrackHandle handle) {
- return static_cast<tr::Track*>(handle);
-}
-
-int FillCodecData(tr::Track* track, const char* codec_data,
- const int codec_data_len) {
- auto* codec_data_ptr = new char[codec_data_len];
- if (codec_data_ptr == nullptr) return -1;
- std::memcpy(codec_data_ptr, codec_data, codec_data_len);
- track->codec_data =
- std::shared_ptr<char>(codec_data_ptr, std::default_delete<char[]>());
- track->codec_data_len = codec_data_len;
- return 0;
-}
-
-bool IsAudioTrackType(const tr::Track* track) {
- return track->type == tr::kTrackTypeAudio;
-}
-bool IsVideoTrackType(const tr::Track* track) {
- return track->type == tr::kTrackTypeVideo;
-}
-bool IsSubtitleTrackType(const tr::Track* track) {
- return track->type == tr::kTrackTypeSubtitle;
-}
-} // namespace
-
-int trackrenderer_track_create(TrackRendererTrackHandle* handle,
- const TrackRendererTrackType type,
- const int index) {
- if (handle == nullptr) return -1;
- *handle = nullptr;
- tr::Track* track = new tr::Track;
- if (track == nullptr) return -1;
- track->type = tr::capi_utils::ConvertToTrackType(type);
- track->index = index;
- *handle = static_cast<TrackRendererTrackHandle>(track);
- return 0;
-}
-
-int trackrenderer_track_destroy(TrackRendererTrackHandle handle) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- delete track;
- return 0;
-}
-
-int trackrenderer_track_set_activation(
- TrackRendererTrackHandle handle,
- const TrackRendererTrackActivation activation) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- track->active =
- activation == kTrackRendererTrackActivationActive ? true : false;
- return 0;
-}
-
-int trackrenderer_track_set_mimetype(TrackRendererTrackHandle handle,
- const char* mimetype) {
- if (handle == nullptr) return -1;
- if (mimetype == nullptr) return -1;
- auto* track = cast_(handle);
- track->mimetype = mimetype;
- return 0;
-}
-
-int trackrenderer_track_set_streamtype(TrackRendererTrackHandle handle,
- const char* streamtype) {
- if (handle == nullptr) return -1;
- if (streamtype == nullptr) return -1;
- auto* track = cast_(handle);
- track->streamtype = streamtype;
- return 0;
-}
-
-int trackrenderer_track_set_codec_data(TrackRendererTrackHandle handle,
- const char* codec_data,
- const int codec_data_len) {
- if (handle == nullptr) return -1;
- if (codec_data == nullptr) return -1;
- if (tr::track_util::IsValidCodecDataSize(codec_data_len) == false) return -1;
- auto* track = cast_(handle);
- if (IsSubtitleTrackType(track)) return -1;
- return FillCodecData(track, codec_data, codec_data_len);
-}
-
-int trackrenderer_track_set_decoder_type(
- TrackRendererTrackHandle handle, const TrackRendererTrackDecoderType type) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsSubtitleTrackType(track)) return -1;
- auto ret = 0;
- switch (type) {
- case kTrackRendererTrackDecoderTypeHwOnly:
- track->use_swdecoder = false;
- break;
- case kTrackRendererTrackDecoderTypeSwOnly:
- track->use_swdecoder = true;
- break;
- default:
- ret = -1;
- break;
- }
- return ret;
-}
-
-int trackrenderer_track_video_set_resolution(TrackRendererTrackHandle handle,
- const int width,
- const int height) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsVideoTrackType(track) == false) return -1;
- track->width = width;
- track->height = height;
- return 0;
-}
-
-int trackrenderer_track_video_set_max_resolution(
- TrackRendererTrackHandle handle, const int width, const int height) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsVideoTrackType(track) == false) return -1;
- track->maxwidth = width;
- track->maxheight = height;
- return 0;
-}
-
-int trackrenderer_track_video_set_framerate(TrackRendererTrackHandle handle,
- const int num, const int den) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsVideoTrackType(track) == false) return -1;
- track->framerate_num = num;
- track->framerate_den = den;
- return 0;
-}
-
-int trackrenderer_track_video_set_codec_tag(TrackRendererTrackHandle handle,
- const char* codec_tag) {
- if (handle == nullptr) return -1;
- if (codec_tag == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsVideoTrackType(track) == false) return -1;
- track->codec_tag = codec_tag;
- return 0;
-}
-
-int trackrenderer_track_video_set_version(TrackRendererTrackHandle handle,
- const int version) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsVideoTrackType(track) == false) return -1;
- track->version = version;
- return 0;
-}
-
-int trackrenderer_track_audio_set_sample_rate(TrackRendererTrackHandle handle,
- const int sample_rate) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->sample_rate = sample_rate;
- return 0;
-}
-
-int trackrenderer_track_audio_set_sample_format(TrackRendererTrackHandle handle,
- const int sample_format) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->sample_format = sample_format;
- return 0;
-}
-
-int trackrenderer_track_audio_set_channels(TrackRendererTrackHandle handle,
- const int channels) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->channels = channels;
- return 0;
-}
-
-int trackrenderer_track_audio_set_version(TrackRendererTrackHandle handle,
- const int version) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->version = version;
- return 0;
-}
-
-int trackrenderer_track_audio_set_layer(TrackRendererTrackHandle handle,
- const int layer) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->layer = layer;
- return 0;
-}
-
-int trackrenderer_track_audio_set_bits_per_sample(
- TrackRendererTrackHandle handle, const int bits_per_sample) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->bits_per_sample = bits_per_sample;
- return 0;
-}
-
-int trackrenderer_track_audio_set_block_align(TrackRendererTrackHandle handle,
- const int block_align) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->block_align = block_align;
- return 0;
-}
-
-int trackrenderer_track_audio_set_bitrate(TrackRendererTrackHandle handle,
- const int bitrate) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->bitrate = bitrate;
- return 0;
-}
-
-int trackrenderer_track_audio_set_layout(TrackRendererTrackHandle handle,
- const char* layout) {
- if (handle == nullptr) return -1;
- if (layout == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->layout = layout;
- return 0;
-}
-
-int trackrenderer_track_audio_set_flavor(TrackRendererTrackHandle handle,
- const int flavor) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->flavor = flavor;
- return 0;
-}
-
-int trackrenderer_track_audio_set_endianness(
- TrackRendererTrackHandle handle,
- const TrackRendererTrackEndianness endianness) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->endianness =
- endianness == kTrackRendererTrackEndiannessLittle ? 1234 : 4321;
- return 0;
-}
-
-int trackrenderer_track_audio_set_signedness(
- TrackRendererTrackHandle handle,
- const TrackRendererTrackSignedness signedness) {
- if (handle == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->is_signed =
- signedness == kTrackRendererTrackSignednessSigned ? true : false;
- return 0;
-}
-
-int trackrenderer_track_audio_set_codec_tag(TrackRendererTrackHandle handle,
- const char* codec_tag) {
- if (handle == nullptr) return -1;
- if (codec_tag == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsAudioTrackType(track) == false) return -1;
- track->codec_tag = codec_tag;
- return 0;
-}
-
-int trackrenderer_track_subtitle_set_language_code(
- TrackRendererTrackHandle handle, const char* language_code) {
- if (handle == nullptr) return -1;
- if (language_code == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsSubtitleTrackType(track) == false) return -1;
- track->language_code = language_code;
- return 0;
-}
-
-int trackrenderer_track_subtitle_set_subtitle_format(
- TrackRendererTrackHandle handle, const char* subtitle_format) {
- if (handle == nullptr) return -1;
- if (subtitle_format == nullptr) return -1;
- auto* track = cast_(handle);
- if (IsSubtitleTrackType(track) == false) return -1;
- track->subtitle_format = subtitle_format;
- return 0;
-}
-// LCOV_EXCL_STOP
#include "trackrenderer/core/track_util.h"
-#include <algorithm>
#include <string>
#include <unordered_map>
-
+#include <inttypes.h>
#include "trackrenderer/core/utils/log.h"
namespace plusplayer {
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 {
+ auto find_target = [type](Track item)->bool {
if (item.type == type && item.active) {
return true;
} else {
auto target = std::find_if(track_list.begin(), track_list.end(), find_target);
if (target == track_list.end()) return false; // There is no target.
*track = *target;
- // TRACKRENDERER_INFO("tracktype : %d, index : %d", track->type,
- // track->index);
+ // TRACKRENDERER_INFO("tracktype : %d, index : %d", track->type, track->index);
return true;
}
return false;
}
if (video > 1 || audio > 1 || text > 1) {
- TRACKRENDERER_ERROR(
- "actived tracks are too much: video(%d), audio(%d), text(%d)", video,
- audio, text);
+ TRACKRENDERER_ERROR("actived tracks are too much: video(%d), audio(%d), text(%d)",
+ video, audio, text);
return false;
}
return true;
TRACKRENDERER_INFO("mimetype: %s", track.mimetype.c_str());
TRACKRENDERER_INFO("streamtype: %s", track.streamtype.c_str());
TRACKRENDERER_INFO("tracktype : %d", track.type);
+ TRACKRENDERER_INFO("stream format: %s", track.stream_format.c_str());
+ TRACKRENDERER_INFO("alignment: %s", track.alignment.c_str());
TRACKRENDERER_INFO("width: %d height : %d", track.width, track.height);
- TRACKRENDERER_INFO("maxwidth: %d maxheight : %d", track.maxwidth,
- track.maxheight);
+ TRACKRENDERER_INFO("maxwidth: %d maxheight : %d", track.maxwidth, track.maxheight);
TRACKRENDERER_INFO("framerate(num : %d den : %d)", track.framerate_num,
- track.framerate_den);
+ track.framerate_den);
TRACKRENDERER_INFO("framerate(codec_data : %p )", track.codec_data.get());
TRACKRENDERER_INFO("framerate(codec_data_len : %d )", track.codec_data_len);
TRACKRENDERER_INFO(
- "sample_rate %d sample_format : %d channel : %d version : %d layer : "
- "%d",
- track.sample_rate, track.sample_format, track.channels, track.version,
- track.layer);
+ "sample_rate %d sample_format : %d channel : %d version : %d layer : %d",
+ track.sample_rate, track.sample_format, track.channels, track.version, track.layer);
TRACKRENDERER_INFO(
- "bits_per_sample %d block_align : %d bitrate : %d endianness : %d "
- "is_signed : %d",
- track.bits_per_sample, track.block_align, track.bitrate, track.endianness,
- track.is_signed);
- TRACKRENDERER_INFO("active %d subtitle_format : %s ", track.active,
- track.subtitle_format.c_str());
+ "bits_per_sample %d block_align : %d bitrate : %d endianness : %d is_signed : %d",
+ track.bits_per_sample, track.block_align, track.bitrate, track.endianness, track.is_signed);
+ TRACKRENDERER_INFO("active %d subtitle_format : %s ", track.active, track.subtitle_format.c_str() );
TRACKRENDERER_INFO("use_swdecoder : %d", track.use_swdecoder);
TRACKRENDERER_INFO("language_code: %s", track.language_code.c_str());
}
uint64_t GetPositionWithinBoundary(const uint64_t duration,
const uint64_t position,
const uint64_t threshold) {
- TRACKRENDERER_DEBUG("duration[%llu] position[%llu] threshold[%llu]", duration,
- position, threshold);
+ TRACKRENDERER_DEBUG("duration[%" PRIu64 "] position[%" PRIu64 "] threshold[%" PRIu64 "]", duration, position, threshold);
+
if (duration < threshold) return position;
uint64_t safe_pos = position;
uint64_t boundary = duration - threshold;
GstMapInfo codec_data_info;
if (gst_buffer_map(buffer, &codec_data_info, GST_MAP_READ)) {
TRACKRENDERER_DEBUG("codec extra data [ %s ]", codec_data_info.data);
- TRACKRENDERER_DEBUG("codec extra data size[ %d ]", codec_data_info.size);
+ TRACKRENDERER_DEBUG("codec extra data size[ %" G_GSIZE_FORMAT "]", 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[]>());
track->codec_data = data;
track->codec_data_len = codec_data_info.size;
} else {
- TRACKRENDERER_WARN("Warning invalid codec extra data size [%d]",
- codec_data_info.size);
+ TRACKRENDERER_WARN("Warning invalid codec extra data size [%" G_GSIZE_FORMAT "]",
+ codec_data_info.size);
}
gst_buffer_unmap(buffer, &codec_data_info);
} else {
#include <map>
#include <thread>
#include <utility>
-
-#ifdef SOUNDBAR_PRODUCT
-#include "avoc_av_audio.h"
-#else
-#include "avoc.h"
-#include "avoc_callback.h"
-#include "avoc_mls.h"
-#endif
-#include "iaudio-control.hpp"
-#include "iniparser.h"
-#include "lwipc.h"
-#include "resource_center.h"
#include "system_info.h"
// performance logs in popup log file
#include <sys/stat.h>
#include <sys/types.h>
// end
-
-#ifndef SOUNDBAR_PRODUCT
-#include <capi-graphics-control.h>
-#endif
-
-#include "trackrenderer/audio_controller/resyncaudio/policies.h"
#include "trackrenderer/core/gst_utils.h"
#include "trackrenderer/core/gstobject_guard.h"
#include "trackrenderer/core/track_util.h"
#include "trackrenderer/core/utils/log.h"
-#include "trackrenderer/core/utils/product_cfg.h"
#include "trackrenderer/display.h"
#include "trackrenderer/error.h"
+#include "trackrenderer/core/gstcaps_builder.h"
#include "trackrenderer/resourcemanager.h"
-#include "trackrenderer/trackrenderer_vconf.h"
-#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
-#include "trackrenderer/subtitle_attr_parser.h"
-#endif
namespace {
constexpr char kTrackRendererPipelineName[] = "TrackRenderer";
constexpr guint64 kMaxByteOfSubtitleSrcQueue = 1024; // 1KB
+constexpr guint64 kMaxBufferOfSubtitleSrcQueue = 3;
const char kPadProbeAudioIdle[] = "AUDIO_IDLE_DOWNSTREAM";
const char kPadProbeAudioBlock[] = "AUDIO_BLOCK_DOWNSTREAM";
const char kPadProbeVideoBlock[] = "VIDEO_BLOCK_DOWNSTREAM";
const char kPadProbeSubtitleBlock[] = "SUBTITLE_BLOCK_DOWNSTREAM";
const char kPadProbeVideoPeekBlock[] = "VIDEO_PEEK_BLOCK_DOWNSTREAM";
-const char kPadProbeVideoDecoded[] = "VIDEO_DECODED_DOWNSTREAM";
-const char kPadProbeVideoDecInputBlock[] = "VIDEO_DECODER_INPUT_DOWNSTREAM";
-
-constexpr char kDecoderPluginConfPath[] = "/etc/multimedia/gst-openmax.conf";
-constexpr char kTzDecoderPluginConfPath[] =
- "/etc/multimedia/gst-tz-openmax.conf";
-constexpr char kPlayerIniPath[] = "/etc/multimedia/mmfw_player.ini";
-
-using ComponentWithCodec = std::pair<std::string, std::string>;
-
-static std::once_flag plugin_loaded;
-static std::map<ComponentWithCodec, std::string> PluginTable; // loadable table
-static bool IsDualSoundMode = false;
-
-enum class DeviceSinkElementType {
- kVideoSink,
- kAudioSink,
- kPcmAudiosink,
-};
-static std::map<DeviceSinkElementType, std::string> SinkPluginTable;
-
-enum class PluginType {
- kHw,
- kSw,
-};
-static std::map<std::string, PluginType> PluginTypeTable;
-
-enum class VideoColorFormat {
- kColorFormatI420,
- kColorFormatNV12,
- kColorFormatYUY2,
- kColorFormatUYVY,
- kColorFormatI422,
- kColorFormatNV16,
- kColorFormatST12,
- kColorFormatSN12
-};
-
-#if 0
-const std::map<ComponentWithCodec, std::string> kPluginMap = {
- // rank = 260
- // "omx_mpeg4dec" also can handle x-h264 --> version is different.
- {{"OMX.SDP.video_decoder.mfc0", "video/mpeg"}, "omx_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-h264"}, "omx_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-h263"}, "omx_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-wmv"}, "omx_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-vp8"}, "omx_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-pn-realvideo"}, "omx_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-avs"}, "omx_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-avs+"}, "omx_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-msmpeg"}, "omx_mpeg4dec"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-xvid"}, "omx_mpeg4dec"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-3ivx"}, "omx_mpeg4dec"},
- {{"OMX.SDP.video_decoder.vr360dec", "video/x-vp9"},
- "omx_uhd_videodec_vr360"},
- {{"OMX.SDP.video_decoder.vr360dec", "video/x-h264"},
- "omx_uhd_videodec_vr360"},
- {{"OMX.SDP.video_decoder.vr360dec", "video/x-av1"},
- "omx_uhd_videodec_vr360"},
- // rank = 259
- // "omx_mpeg4dec_1" also can handle x-h264 --> version is different.
- {{"OMX.SDP.video_decoder.mfc1", "video/mpeg"}, "omx_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-h264"}, "omx_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-h263"}, "omx_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-wmv"}, "omx_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-vp8"}, "omx_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-pn-realvideo"}, "omx_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-avs"}, "omx_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-avs+"}, "omx_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-msmpeg"}, "omx_mpeg4dec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-xvid"}, "omx_mpeg4dec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-3ivx"}, "omx_mpeg4dec_1"},
- // rank = 258
- {{"OMX.SDP.video_decoder.mfc2", "video/x-h264"}, "omx_videodec_2"},
- // rank = 257
- {{"OMX.SDP.video_decoder.mfc3", "video/x-h264"}, "omx_videodec_3"},
- // rank = 256
- {{"OMX.SDP.video_decoder.mfc4", "video/x-h264"}, "omx_videodec_4"},
- // rank = 258
- {{"OMX.SDP.video_decoder.dvde0", "video/x-h264"}, "omx_uhd_videodec"},
- {{"OMX.SDP.video_decoder.dvde0", "video/x-vp9"}, "omx_uhd_videodec"},
- {{"OMX.SDP.video_decoder.dvde0", "video/x-h265"}, "omx_uhd_videodec"},
- {{"OMX.SDP.video_decoder.dvde0", "video/x-av1"}, "omx_uhd_videodec"},
- {{"OMX.SDP.video_decoder.hevc8k", "video/x-h265"}, "omx_uhd8k_videodec"},
- {{"OMX.SDP.video_decoder.hevc8k", "video/x-av1"}, "omx_uhd8k_videodec"},
- // TODO: add switch 4K 8K logic
- // rank = 257
- {{"OMX.SDP.video_decoder.dvde1", "video/x-vp9"}, "omx_videodec_5"},
- {{"OMX.SDP.video_decoder.dvde1", "video/x-h265"}, "omx_videodec_5"},
- // rank = 260
- // "omx_uhd_mjpegdec" also can handle x-h265 --> resolution is different.
- {{"OMX.SDP.video_decoder.mjpeg", "video/x-jpeg"}, "omx_mjpegdec"},
- // rand = 259
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/mpeg"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-aac"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-true-hd"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-ac3"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-eac3"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/ac3"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-ac4"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-adpcm"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-wma"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-vorbis"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-pn-realaudio"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-gst-fourcc-mha1"},
- "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-gst-fourcc-mhm1"},
- "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-alaw"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-mulaw"}, "omx_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-opus"}, "omx_audiodec"},
-
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/mpeg"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-aac"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-true-hd"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-ac3"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-eac3"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/ac3"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-ac4"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-adpcm"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-wma"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-vorbis"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-pn-realaudio"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-gst-fourcc-mha1"},
- "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-gst-fourcc-mhm1"},
- "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-alaw"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-mulaw"}, "omx_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-opus"}, "omx_audiodec_1"},
- // rand = 258
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/mpeg"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-aac"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-true-hd"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-ac3"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-eac3"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/ac3"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-ac4"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-adpcm"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-wma"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-vorbis"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-pn-realaudio"},
- "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-gst-fourcc-mha1"},
- "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-gst-fourcc-mhm1"},
- "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-alaw"}, "omx_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-mulaw"}, "omx_mmaudiodec"},
- // tz case
- {{"OMX.SDP.video_decoder.mfc0", "video/mpeg_tz"}, "omx_tz_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-h264_tz"}, "omx_tz_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-h263_tz"}, "omx_tz_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-wmv_tz"}, "omx_tz_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-vp8_tz"}, "omx_tz_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-pn-realvideo_tz"},
- "omx_tz_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-avs_tz"}, "omx_tz_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-avs+_tz"}, "omx_tz_videodec_0"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-msmpeg_tz"}, "omx_tz_mpeg4dec"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-xvid_tz"}, "omx_tz_mpeg4dec"},
- {{"OMX.SDP.video_decoder.mfc0", "video/x-3ivx_tz"}, "omx_tz_mpeg4dec"},
- {{"OMX.SDP.video_decoder.mfc1", "video/mpeg_tz"}, "omx_tz_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-h264_tz"}, "omx_tz_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-h263_tz"}, "omx_tz_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-wmv_tz"}, "omx_tz_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-vp8_tz"}, "omx_tz_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-pn-realvideo_tz"},
- "omx_tz_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-avs_tz"}, "omx_tz_videodec_1"},
- {{"OMX.SDP.video_decoder.mfc1", "video/x-avs+_tz"}, "omx_tz_videodec_1"},
- {{"OMX.SDP.video_decoder.dvde0", "video/x-h264_tz"}, "omx_tz_uhd_videodec"},
- {{"OMX.SDP.video_decoder.dvde0", "video/x-vp9_tz"}, "omx_tz_uhd_videodec"},
- {{"OMX.SDP.video_decoder.dvde0", "video/x-h265_tz"}, "omx_tz_uhd_h265dec"},
- {{"OMX.SDP.video_decoder.dvde0", "video/x-av1_tz"}, "omx_tz_uhd_videodec"},
- {{"OMX.SDP.video_decoder.hevc8k", "video/x-h265_tz"},
- "omx_tz_uhd8k_videodec"},
- {{"OMX.SDP.video_decoder.hevc8k", "video/x-av1_tz"},
- "omx_tz_uhd8k_videodec"},
- {{"OMX.SDP.video_decoder.dvde1", "video/x-vp9_tz"}, "omx_tz_videodec_5"},
- {{"OMX.SDP.video_decoder.dvde1", "video/x-h265_tz"}, "omx_tz_videodec_5"},
- {{"OMX.SDP.video_decoder.mjpeg", "video/x-jpeg_tz"}, "omx_tz_mjpegdec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/mpeg_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-aac_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-ac3_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-eac3_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/ac3_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-ac4_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-adpcm_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-wma_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-vorbis_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-alaw_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-mulaw_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-gst-fourcc-mha1_tz"},
- "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-gst-fourcc-mhm1_tz"},
- "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-opus_tz"}, "omx_tz_audiodec"},
- {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-raw_tz"}, "omx_tz_lpcmdec"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/mpeg_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-aac_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-ac3_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-eac3_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/ac3_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-ac4_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-adpcm_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-wma_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-vorbis_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-alaw_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-mulaw_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-gst-fourcc-mha1_tz"},
- "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-gst-fourcc-mhm1_tz"},
- "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-opus_tz"}, "omx_tz_audiodec_1"},
- {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-raw_tz"}, "omx_tz_lpcmdec_1"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/mpeg_tz"}, "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-aac_tz"}, "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-ac3_tz"}, "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-eac3_tz"},
- "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/ac3_tz"}, "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-ac4_tz"}, "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-adpcm_tz"},
- "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-wma_tz"}, "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-vorbis_tz"},
- "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-pn-realaudio_tz"},
- "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-gst-fourcc-mha1_tz"},
- "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-gst-fourcc-mhm1_tz"},
- "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-alaw_tz"},
- "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-mulaw_tz"},
- "omx_tz_mmaudiodec"},
- {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-raw_tz"}, "omx_tz_mmaudiodec"},
- // SW decoder
- {{"FFMPEG.SW.Decoder", "video/audio"}, "ffdec_xxx"}, };
-#endif
-
-using ComponentWithSwCodec = std::pair<std::string, int>; // mime,version
-const std::map<ComponentWithSwCodec, std::string> kSwPluginMap = {
- {{"video/mpeg", 1}, "ffdec_mpeg1video"},
- {{"video/mpeg", 2}, "ffdec_mpeg2video"},
- {{"video/mpeg", 4}, "ffdec_mpeg4"},
- {{"video/x-h264", 0}, "ffdec_h264"},
- {{"video/x-vp9", 0}, "ffdec_vp9"},
- {{"video/x-vp8", 0}, "ffdec_vp8"},
- {{"video/x-vp6", 0}, "ffdec_vp6"},
- {{"video/x-h265", 0}, "ffdec_hevc"},
- {{"video/x-msmpeg", 41}, "ffdec_msmpeg4v1"},
- {{"video/x-msmpeg", 42}, "ffdec_msmpeg4v2"},
- {{"video/x-msmpeg", 43}, "ffdec_msmpeg4"},
- {{"video/x-wmv", 1}, "ffdec_wmv1"},
- {{"video/x-wmv", 2}, "ffdec_wmv2"},
- {{"video/x-wmv", 3}, "ffdec_wmv3"},
- {{"audio/mpeg", 1}, "ffdec_mp3"},
- {{"audio/x-opus", 0}, "ffdec_opus"},
- {{"audio/mpeg", 2}, "ffdec_aac"},
- {{"audio/mpeg", 4}, "ffdec_aac"},
- {{"audio/x-ac3", 0}, "ffdec_ac3"},
- {{"audio/x-eac3", 0}, "ffdec_eac3"},
- {{"audio/x-wma", 1}, "ffdec_wmav1"},
- {{"audio/x-wma", 2}, "ffdec_wmav2"},
- {{"audio/x-mulaw", 0}, "ffdec_pcm_mulaw"},
-};
-
-using ComponentWithMpeg4VideoCodec = std::pair<std::string, std::string>;
-using Mpeg4VidoePluginMapType =
- std::map<ComponentWithMpeg4VideoCodec, std::string>;
-
-const Mpeg4VidoePluginMapType kMpeg4VidoePluginMap = {
- {{"OMX.SDP.video_decoder.mfc0", "video/mpeg"}, "omx_mpeg4dec"},
- {{"OMX.SDP.video_decoder.mfc1", "video/mpeg"}, "omx_mpeg4dec_1"},
- {{"OMX.SDP.video_decoder.mfc0", "video/mpeg_tz"}, "omx_tz_mpeg4dec"},
- {{"OMX.SDP.video_decoder.mfc1", "video/mpeg_tz"}, "omx_tz_mpeg4dec_1"},
-};
+const char kPadProbeCapsEvent[] = "CAPS_EVENT_DOWNSTREAM";
+const char kPadProbeAppsrcEvent[] = "APPSRC_EVENT_DOWNSTREAM";
// Hw clock
#ifndef PR_TASK_PERF_USER_TRACE
namespace internal {
enum class TrackEncryptionUnit { kNone, kTs, kEs };
-// LCOV_EXCL_START
+
void TvplusPerformanceLogs() {
FILE* fp = NULL;
const char* TVPLUS_POPUP_LOG_FILE_NAME = "/tmp/play_log.txt";
TRACKRENDERER_DEBUG("~~~~~~~~~~~~~ file write failed ~~~~~~~~~~~~~~~~");
}
}
-// LCOV_EXCL_STOP
bool IsSdkEnabledFeature() {
#ifdef SDK_ENABLED_FEATURE
return false;
}
-void GetSoundMode() {
- int ret = system_info_get_custom_bool(
- "com.samsung/featureconf/multiview.dualsound", &IsDualSoundMode);
- if (SYSTEM_INFO_ERROR_NONE != ret) {
- TRACKRENDERER_ERROR("system_info_get_custom_bool() return error[%d]", ret);
- }
+inline bool IsPcmMimeType(const std::string& mimetype) {
+ return (mimetype.find("audio/x-raw") != std::string::npos);
+}
+
+const char* GetAudioSinkPluginName(bool swdecoder,
+ const std::string& mimetype) {
+ return "pulsesink";
}
-inline bool IsHwPlugin(const char* plugin_name) {
- if (PluginTypeTable.count(plugin_name) > 0) {
- if (PluginTypeTable[plugin_name] == ::PluginType::kHw) return true;
+const char* GetIniElement(const std::map<std::string, std::string>& elements,
+ const std::string& key) {
+ auto look = elements.find(key);
+ if (look == elements.end()) {
+ return nullptr;
}
- return false;
+
+ if (look->second.length() == 0)
+ return nullptr;
+
+ return look->second.c_str();
}
-inline bool IsPcmMimeType(const std::string& mimetype) {
- return (mimetype == "audio/x-raw");
+const char* GetVideoSinkPluginName(const std::map<std::string, std::string>& ini_elements,
+ bool swdecoder) {
+ const char* videosink = GetIniElement(ini_elements, "videosink_element_overlay");
+ if (!videosink)
+ return "tizenwlsink";
+
+ return videosink;
}
void GetIniValue(const std::map<std::string, bool>& properties,
return (w > kMaxUhdWidth || h > kMaxUhdHeight);
}
-inline bool IsAacCodec(const Track& track) {
- return (track.mimetype.find("audio/mpeg") != std::string::npos &&
- track.version == 2);
-}
-
-inline bool IsEac3Codec(const std::string& mimetype) {
- return mimetype.find("audio/x-eac3") != std::string::npos;
-}
-
-inline bool IsAc3Codec(const std::string& mimetype) {
- return mimetype.find("audio/x-ac3") != std::string::npos;
-}
-
inline bool IsTzMimeType(const std::string& mimetype) { // useful when external
// audio is present in
// verimatrix case as trustzone is not used in this case
return (mimetype.find("_tz") != std::string::npos);
}
-inline bool IsVideoRawMimeType(const std::string& mimetype) {
- return (mimetype.find("video/x-raw") != std::string::npos);
-}
-
inline bool IsExternalDecryptionCase(const drm::Property& property) {
return property.external_decryption;
}
IsTzMimeType(mimetype));
}
+inline bool IsDecryptorElementNecessary(const drm::Property& property) {
+ return (property.type == drm::Type::kClearkey);
+
+}
inline bool IsTzDecoderElementNecessary(const drm::Property& property,
const std::string& mimetype) {
return IsTzMimeType(mimetype);
}
inline bool IsDecoderElementNecessary(const std::string& mimetype) {
- return !IsPcmMimeType(mimetype) && !IsVideoRawMimeType(mimetype);
+ return !IsPcmMimeType(mimetype);
}
-inline bool IsDecodedVideoBufferNeeded(DecodedVideoFrameBufferType& type) {
+inline bool IsVideoDecodedBufferNeeded(DecodedVideoFrameBufferType& type) {
return (type != DecodedVideoFrameBufferType::kNone);
}
-
-inline bool IsDisplayNeeded(DisplayType& type) {
- return (type != DisplayType::kNone);
-}
-
-inline bool IsAvailableCodecChange(const Track& track) {
- if (internal::IsAacCodec(track) || internal::IsAc3Codec(track.mimetype) ||
- internal::IsEac3Codec(track.mimetype))
- return true;
- return false;
-}
-
constexpr int kVideoBufferPlaneMax = 4;
struct VideoStreamDataType {
tbm_format format = TBM_FORMAT_NV12; //< image format
- Geometry crop_area; //< crop info of video buffer
int width = 0; //< width of video buffer
int height = 0; //< height of video buffer
tbm_bo bo[kVideoBufferPlaneMax] = {nullptr}; //< TBM buffer object
int elevation[kVideoBufferPlaneMax] = {0}; //< elevation of plane
};
-void SetGeometry(Geometry* geom, const int& x, const int& y, const int& w,
- const int& h) {
- geom->x = x;
- geom->y = y;
- geom->w = w;
- geom->h = h;
- return;
-}
-
bool CopySwCodec(GstBuffer* decodedBuffer, const VideoStreamDataType& stream) {
tbm_bo bo_Y = stream.bo[GST_VIDEO_COMP_Y];
tbm_bo bo_C = stream.bo[GST_VIDEO_COMP_U];
return true;
}
-bool CopyHwCodec(const VideoStreamDataType& stream, int y_viraddr,
- int c_viraddr, int y_linesize, int c_linesize,
- VideoColorFormat color_format) {
+bool CopyHwCodec(const VideoStreamDataType& stream, uintptr_t y_viraddr,
+ uintptr_t c_viraddr, int y_linesize, int c_linesize) {
tbm_bo bo_Y = stream.bo[GST_VIDEO_COMP_Y];
tbm_bo bo_C = stream.bo[GST_VIDEO_COMP_U];
+
tbm_bo_handle bo_handle_Y =
tbm_bo_map(bo_Y, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
if (!bo_handle_Y.ptr) {
for (int i = 0; i < stream.height; i++) {
memcpy((unsigned char*)(bo_handle_Y.ptr) +
(i * stream.stride[GST_VIDEO_COMP_Y]),
- (unsigned char*)y_viraddr, stream.width);
+ (void *)y_viraddr, stream.width);
y_viraddr += y_linesize;
}
tbm_bo_unmap(bo_Y);
TRACKRENDERER_ERROR("TBM get error : bo_handle_C.ptr is NULL");
return false;
}
- if (color_format ==
- VideoColorFormat::kColorFormatNV16) { // NV16, convert to NV12
- for (int i = 0; i < stream.height / 2; i++) {
- memcpy((unsigned char*)(bo_handle_C.ptr) +
- (i * stream.stride[GST_VIDEO_COMP_U]),
- (unsigned char*)c_viraddr, stream.width);
- c_viraddr += c_linesize * 2;
- }
- } else if (color_format == VideoColorFormat::kColorFormatNV12) { // NV12
- for (int i = 0; i < stream.height / 2; i++) {
- memcpy((unsigned char*)(bo_handle_C.ptr) +
- (i * stream.stride[GST_VIDEO_COMP_U]),
- (unsigned char*)c_viraddr, stream.width);
- c_viraddr += c_linesize;
- }
+ for (int i = 0; i < stream.height / 2; i++) {
+ memcpy((unsigned char*)(bo_handle_C.ptr) +
+ (i * stream.stride[GST_VIDEO_COMP_U]),
+ (void *)c_viraddr, stream.width);
+ c_viraddr += c_linesize;
}
tbm_bo_unmap(bo_C);
+
return true;
}
return tbm_surf;
}
-#ifdef SOUNDBAR_PRODUCT
-bool ScaleHwCodecWithGa(tbm_bufmgr bufmgr, const VideoStreamDataType& stream,
- int y_phyaddr, int c_phyaddr, int y_linesize,
- int c_linesize, VideoColorFormat color_format) {
- return false;
-}
-#else
-bool TbmScale(tbm_bufmgr bufmgr, Graphics_ColorFormat_k colorMode,
- std::uint32_t src_handle, const Geometry& src_rect,
- int src_linesize, std::uint32_t dst_handle,
- const Geometry& dst_rect, int dst_linesize) {
- GraphicsGAScaleInfo ga_info;
- memset(&ga_info, 0, sizeof(GraphicsGAScaleInfo));
-
- ga_info.ga_mode = GRAPHICS_GA_SCALE_MODE;
- ga_info.rop_mode = GRAPHICS_GA_ROP_COPY;
- ga_info.ga_op_type = GRAPHICS_GA_SCALE;
- ga_info.pre_alphamode = 0;
- ga_info.ca_value = 0;
- ga_info.rop_on_off = 0;
- ga_info.color_format = colorMode;
-
- ga_info.src_handle = src_handle;
- ga_info.src_hbytesize = src_linesize;
- ga_info.src_rect.x = src_rect.x;
- ga_info.src_rect.y = src_rect.y;
- ga_info.src_rect.w = src_rect.w;
- ga_info.src_rect.h = src_rect.h;
-
- ga_info.dst_handle = dst_handle;
- ga_info.dst_hbytesize = dst_linesize;
- ga_info.dst_rect.x = dst_rect.x;
- ga_info.dst_rect.y = dst_rect.y;
- ga_info.dst_rect.w = dst_rect.w;
- ga_info.dst_rect.h = dst_rect.h;
-
- if (Gfx_GA_Scale(bufmgr, &ga_info) < 0) {
- TRACKRENDERER_ERROR("Gfx_GA_Scale fail");
- return false;
- }
- return true;
-}
-
-bool ScaleHwCodecWithGa(tbm_bufmgr bufmgr, const VideoStreamDataType& stream,
- int y_phyaddr, int c_phyaddr, int y_linesize,
- int c_linesize, VideoColorFormat color_format) {
- Geometry src_rect, dst_rect;
-
- tbm_bo bo_Y = stream.bo[GST_VIDEO_COMP_Y];
- tbm_bo bo_C = stream.bo[GST_VIDEO_COMP_U];
- tbm_bo_handle bo_handle_Y = tbm_bo_get_handle(bo_Y, TBM_DEVICE_2D);
- if (!bo_handle_Y.u32) {
- TRACKRENDERER_ERROR("TBM get error : bo_handle_Y.u32 is NULL");
- return false;
- }
-
- tbm_bo_handle bo_handle_C = tbm_bo_get_handle(bo_C, TBM_DEVICE_2D);
- if (!bo_handle_C.u32) {
- TRACKRENDERER_ERROR("TBM get error : bo_handle_C.u32 is NULL");
- return false;
- }
-
- SetGeometry(&src_rect, stream.crop_area.x, stream.crop_area.y,
- stream.crop_area.w, stream.crop_area.h);
- SetGeometry(&dst_rect, 0, 0, stream.width, stream.height);
- if (!TbmScale(bufmgr, GRAPHICS_GA_FORMAT_8BPP, y_phyaddr, src_rect,
- y_linesize, bo_handle_Y.u32, dst_rect,
- stream.stride[GST_VIDEO_COMP_Y])) {
- TRACKRENDERER_ERROR("Y data Ga copy fail");
- return false;
- }
-
- if (color_format == VideoColorFormat::kColorFormatNV16) { // NV16
- SetGeometry(&src_rect, stream.crop_area.x / 2, stream.crop_area.y,
- stream.crop_area.w / 2, stream.crop_area.h);
- SetGeometry(&dst_rect, 0, 0, stream.width / 2, stream.height / 2);
- } else if (color_format == VideoColorFormat::kColorFormatNV12) { // NV12
- SetGeometry(&src_rect, stream.crop_area.x / 2, stream.crop_area.y / 2,
- stream.crop_area.w / 2, stream.crop_area.h / 2);
- SetGeometry(&dst_rect, 0, 0, stream.width / 2, stream.height / 2);
- }
- if (!TbmScale(bufmgr, GRAPHICS_GA_FORMAT_16BPP, c_phyaddr, src_rect,
- c_linesize, bo_handle_C.u32, dst_rect,
- stream.stride[GST_VIDEO_COMP_U])) {
- TRACKRENDERER_ERROR("UV data Ga copy fail");
- return false;
- }
- return true;
-}
-#endif
-
int ToBufferTypeForSink(const DecodedVideoFrameBufferType& type) {
// 0:copy, 1:reference, -1:none (refer to gstwaylnadsink)
constexpr int kCopy = 0;
constexpr std::uint32_t kAVSync = 0x0100;
return (low_latency_mode & kAVSync) ? true : false;
}
-inline bool IsLowLatencyModeDisablePreroll(std::uint32_t low_latency_mode) {
- constexpr std::uint32_t kPreroll = 0x0200;
- return (low_latency_mode & kPreroll) ? true : false;
-}
-// LCOV_EXCL_START
int GetVideoWidth(const GstCaps* caps) {
GstStructure* structure = gst_caps_get_structure(caps, 0);
if (!structure) return 0;
return height;
}
-// LCOV_EXCL_STOP
-
-void LoadDecoderPluginTable_(const char* path) {
- gchar* config = nullptr;
- if (!g_file_get_contents(path, &config, nullptr, nullptr)) {
- TRACKRENDERER_ERROR("could not find config file!");
- return;
- }
-
- GstStructure* element_table =
- gst_structure_new_empty("element_table"); // leak caution
- GstStructure* element = nullptr;
- gchar* start = config;
-
- while ((element = gst_structure_from_string(start, &start))) {
- const gchar* element_name = gst_structure_get_name(element);
- gst_structure_set(element_table, element_name, GST_TYPE_STRUCTURE, element,
- nullptr);
- }
-
- unsigned int cnt = gst_structure_n_fields(element_table);
- for (unsigned int i = 0; i < cnt; i++) {
- const gchar* element_name = gst_structure_nth_field_name(element_table, i);
- gst_structure_get(element_table, element_name, GST_TYPE_STRUCTURE, &element,
- nullptr);
- const gchar* component_name =
- gst_structure_get_string(element, "component-name");
- const gchar* sink_caps = gst_structure_get_string(element, "sink");
- // TRACKRENDERER_ERROR("plugin name [%s] comp-name [%s]", element_name,
- // component_name);
- ::PluginTypeTable.emplace(element_name, PluginType::kHw);
-
- std::string caps_str(sink_caps);
- std::size_t offset = 0;
- while (1) {
- // TRACKRENDERER_ERROR("offset %d", offset);
- std::size_t start_pos = caps_str.find("video/", offset);
- if (start_pos == std::string::npos) {
- start_pos = caps_str.find("audio/", offset);
- if (start_pos == std::string::npos) break;
- }
-
- std::string mimetype;
- std::size_t end_pos = caps_str.find(';', start_pos);
- if (end_pos == std::string::npos) {
- end_pos = caps_str.find(',', start_pos);
- if (end_pos == std::string::npos) {
- mimetype = caps_str.substr(start_pos);
- } else {
- mimetype = caps_str.substr(start_pos, end_pos - start_pos);
- }
- // TRACKRENDERER_ERROR("parsed mimetype :: %s", mimetype.c_str());
- ::PluginTable.emplace(
- std::pair<std::string, std::string>(component_name, mimetype),
- element_name);
- break; // last item or only one item.
- } else {
- // gen sub string video/ or audio/ ~ ';'
- std::string sub_caps_str =
- caps_str.substr(start_pos, end_pos - start_pos);
- // TRACKRENDERER_ERROR("sub str :: %s >>> start pos[%d] end
- // pos [%d]", sub_caps_str.c_str(), start_pos, end_pos);
- std::size_t sub_end_pos = sub_caps_str.find(',');
- if (sub_end_pos == std::string::npos) {
- mimetype = sub_caps_str;
- } else {
- mimetype = sub_caps_str.substr(0, sub_end_pos);
- }
- ::PluginTable.emplace(
- std::pair<std::string, std::string>(component_name, mimetype),
- element_name);
- }
- offset = end_pos;
- // TRACKRENDERER_ERROR("start pos [%d], end pos [%d]", start_pos,
- // end_pos);
- // TRACKRENDERER_ERROR("parsed mimetype :: %s", mimetype.c_str());
- }
- }
- gst_structure_free(element_table);
-}
-
-std::string GetIniString(dictionary* dict, const char* key, char* default_val) {
- const gchar* value = iniparser_getstring(dict, key, default_val);
- constexpr int kMaxIniStrLen = 100;
- if (value && strlen(value) > 0 && strlen(value) < kMaxIniStrLen) {
- return value;
- } else {
- return {};
- }
-}
-
-void LoadSinkPluginTable() {
- dictionary* dict = nullptr;
- dict = iniparser_load(kPlayerIniPath);
- if (!dict) {
- TRACKRENDERER_ERROR("Fail to load ini file");
- return;
- }
-
- char default_video_sink_name[] = "directvideosink";
- SinkPluginTable.emplace(
- DeviceSinkElementType::kVideoSink,
- GetIniString(dict, "general:videosink element overlay",
- default_video_sink_name));
-
- char default_audio_sink_name[] = "mmaudiosink";
- SinkPluginTable.emplace(
- DeviceSinkElementType::kAudioSink,
- GetIniString(dict, "general:audiosink element", default_audio_sink_name));
-
- SinkPluginTable.emplace(DeviceSinkElementType::kPcmAudiosink,
- GetIniString(dict, "general:pcmaudiosink element",
- default_audio_sink_name));
-}
-
-void LoadPluginTable() {
- LoadDecoderPluginTable_(kDecoderPluginConfPath);
- LoadDecoderPluginTable_(kTzDecoderPluginConfPath);
- LoadSinkPluginTable();
- GetSoundMode();
-
- /*
- for (auto& item : ::PluginTable) {
- TRACKRENDERER_ERROR(" PluginTable :: [%s][%s][%s]",
- (item.first).first.c_str(),
- (item.first).second.c_str(), item.second.c_str());
- }
-
- for (auto& item : ::PluginTypeTable) {
- TRACKRENDERER_ERROR(" PluginTypeTable :: [%s][%d]", (item.first).c_str(),
- static_cast<int>(item.second));
- }
- */
- for (auto& item : ::SinkPluginTable) {
- TRACKRENDERER_ERROR(" SinkPluginTable :: [%d][%s]",
- static_cast<int>(item.first), (item.second).c_str());
- }
-}
-
-bool CheckMpeg4Video(const std::string& mime_type, const int version) {
- const std::string video_mpeg = "video/mpeg";
- return ((mime_type.find(video_mpeg) != std::string::npos) && version == 4);
-}
-
-int GetAvocSourceType(bool is_main_device, bool swdecoder,
- const std::string& mimetype) {
- if (swdecoder || internal::IsPcmMimeType(mimetype)) return AUDIO_MM;
- int sec_ctl_source =
- is_main_device ? AUDIO_MULTIMEDIA_DEC0 : AUDIO_MULTIMEDIA_DEC1;
- return sec_ctl_source;
-}
-
-int GetAudioOut(bool is_main_device) {
- constexpr int kAudioMainOut = 0;
- constexpr int kAudioSubOut = 1;
- int audio_out = (is_main_device) ? kAudioMainOut : kAudioSubOut;
- return audio_out;
-}
-
-bool FillVideoStreamDataAndTbmSurface(internal::VideoStreamDataType* stream,
- tbm_surface_h* tbm_surf_t,
- const int width, const int height) {
- if (stream == nullptr || tbm_surf_t == nullptr) {
- TRACKRENDERER_ERROR("stream[%p] or tbm_surf_t[%p] is nullptr", stream,
- tbm_surf_t);
- return false;
- }
-
- stream->format = TBM_FORMAT_NV12;
- stream->width = width;
- stream->height = height;
- stream->elevation[GST_VIDEO_COMP_Y] = height;
- stream->elevation[GST_VIDEO_COMP_U] = height / 2;
-
- *tbm_surf_t =
- tbm_surface_create(stream->width, stream->height, TBM_FORMAT_NV12);
-
- tbm_surface_internal_get_plane_data(
- *tbm_surf_t, GST_VIDEO_COMP_Y, NULL, NULL,
- (uint32_t*)&stream->stride[GST_VIDEO_COMP_Y]);
- tbm_surface_internal_get_plane_data(
- *tbm_surf_t, GST_VIDEO_COMP_U, NULL, NULL,
- (uint32_t*)&stream->stride[GST_VIDEO_COMP_U]);
-
- stream->bo[GST_VIDEO_COMP_Y] =
- tbm_surface_internal_get_bo(*tbm_surf_t, GST_VIDEO_COMP_Y);
- if (!stream->bo[GST_VIDEO_COMP_Y]) {
- TRACKRENDERER_ERROR("[bo Y] tbm_surface_internal_get_bo failed");
- return false;
- }
-
- stream->bo[GST_VIDEO_COMP_U] =
- tbm_surface_internal_get_bo(*tbm_surf_t, GST_VIDEO_COMP_U);
- if (!stream->bo[GST_VIDEO_COMP_U]) {
- TRACKRENDERER_ERROR("[bo C] tbm_surface_internal_get_bo failed");
- return false;
- }
- return true;
-}
} // namespace internal
TrackRenderer::TrackRenderer() noexcept : caps_builder_(kCapsRecipes_) {
resource_manager_.reset(new ResourceManager(this));
display_.reset(new Display);
- TRACKRENDERER_DEBUG_P(this, "Display instance > %p", display_.get());
- screen_saver_.reset(new ScreenSaver);
- latency_manager_.reset(new LatencyManager(this));
- resync_audio_policy_.reset(new resync_audio::DummyPolicy());
playback_info_ = debug::PlayinfoSetter::Create();
SetDefaultAttributeValue_();
InitConfigSetterTable_();
- std::call_once(::plugin_loaded, [this]() { internal::LoadPluginTable(); });
}
-TrackRenderer::~TrackRenderer() {
- TRACKRENDERER_ENTER_P(this);
- resource_manager_.reset();
- latency_manager_.reset();
- UnsetVconfCb_();
- TRACKRENDERER_LEAVE_P(this);
-}
+TrackRenderer::~TrackRenderer() {}
bool TrackRenderer::Start() {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+
if (state_ == State::kStopped) return false;
if (state_ == State::kResourceConflicted) return true;
if (!pipeline_) {
}
*/
pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
- pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
if (state_ < State::kWorking) return false;
target_substate_ = SubState::kPlaying;
pipeline_->SetState(Elements::kPipeline, GST_STATE_PLAYING);
internal::GetIniValue(properties_, "generate_dot", &value);
if (value) pipeline_->GenerateDot("plusplayer_trackrenderer_start");
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
bool TrackRenderer::Stop() {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
resource_cv_.notify_one();
if (state_ == State::kStopped) {
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
if (state_ != State::kResourceConflicted) state_ = State::kStopped;
if (!pipeline_) {
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
/*
pipeline_->SetProperty(Elements::kSinkVideo, "still-mode", TRUE);
}
*/
- TRACKRENDERER_INFO_P(this, "Set pipeline state to GST_STATE_NULL.");
- UnsetResourceCenterCallback_();
- StopAudioEasing_();
+ TRACKRENDERER_INFO("Set pipeline state to GST_STATE_NULL.");
pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
- pipeline_->PadRemoveProbe(kPadProbeVideoDecoded);
- pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
pipeline_->SetState(Elements::kPipeline, GST_STATE_NULL);
- SetVr360GpuModeSecure_(false);
ReleaseResource_();
playback_info_->VconfSetMsgHide();
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
gst_caps_set_simple(new_caps_guard.get(), "maxwidth", G_TYPE_INT, max_w,
"maxheight", G_TYPE_INT, max_h, NULL);
- TRACKRENDERER_INFO_P(this, "max widh [%d], max height [%d]", max_w, max_h);
+ TRACKRENDERER_INFO("max widh [%d], max height [%d]", max_w, max_h);
display_->SetDisplayQualityInfo(new_caps_guard.get());
}
bool TrackRenderer::Prepare() {
- TRACKRENDERER_ENTER_E_P(this);
+ TRACKRENDERER_ENTER_E;
std::unique_lock<std::mutex> lock(resource_m_);
- std::unique_lock<std::mutex> audio_lk(internal_audio_m_);
if (state_ == State::kStopped) {
- TRACKRENDERER_ERROR_P(this, "already stopped");
- return false;
- }
- SetVconfCb_();
-
- if (AvocPlayerRegister_() == false) {
- TRACKRENDERER_ERROR_P(this, "AvocPlayerRegister_() failed");
+ TRACKRENDERER_ERROR("already stopped");
return false;
}
- SetResourceCenterCallback_();
-
::PerfUsrTrace("Prepare GetResource");
- if (GetResource_(kTrackTypeMax) == false) {
- TRACKRENDERER_ERROR_P(this, "resource acquire failed.");
+ if (GetResource_() == false) {
+ TRACKRENDERER_ERROR("resource acquire failed.");
ReleaseResource_();
return false;
}
- SetVr360GpuModeSecure_(true);
::PerfUsrTrace("Prepare CreatePipeline");
if (CreatePipeline_() == false) {
- TRACKRENDERER_ERROR_P(this, "renderer pipeline creation failed");
- return false;
- }
-
- latency_manager_->SetPipeline(pipeline_.get());
- if (!AvocPlayRequest_()) {
- TRACKRENDERER_ERROR_P(this, "AvocPlayRequest_() failed");
+ TRACKRENDERER_ERROR("renderer pipeline creation failed");
return false;
}
- ::PerfUsrTrace("Prepare InitAvoc end");
-
- SetAudioOut_();
int max_width = 0;
int max_height = 0;
if (internal::IsUhd8kResolution(max_width, max_height)) {
constexpr uint32_t kAdaptiveStreaming8kMode =
0x80; // refer to waylandsink properity value.
- TRACKRENDERER_INFO_P(this, "Set 8K Video quality mode : 0x80");
+ TRACKRENDERER_INFO("Set 8K Video quality mode : 0x80");
display_->SetVideoQualityMode(kAdaptiveStreaming8kMode);
}
::PerfUsrTrace("Prepare SetVideoQualityInfo_ begin");
SetVideoQualityInfo_();
::PerfUsrTrace("Prepare SetVideoQualityInfo_ end");
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+ pipeline_->Execute(Elements::kSinkVideo, [this](GstElement* obj) noexcept {
return display_->Update(obj);
});
auto audio_delay_info = gstguard::make_guard(gst_structure_new(
"audio-delay-info", "video-max-width", G_TYPE_UINT, max_width,
"video-max-height", G_TYPE_UINT, max_height, NULL));
- TRACKRENDERER_INFO_P(this, "Set AudioDelayInformation v_res [%d x %d]",
- max_width, max_height);
- pipeline_->SetProperty(Elements::kSinkAudio, "audio-delay-info-for-avsync",
- audio_delay_info.get());
+ TRACKRENDERER_INFO("Set AudioDelayInformation v_res [%d x %d]", max_width,
+ max_height);
+
+ //TODO: should be enabled audio
+ //pipeline_->SetProperty(Elements::kSinkAudio, "audio-delay-info-for-avsync",
+ // audio_delay_info.get());
if (!pipeline_->SetState(Elements::kPipeline, GST_STATE_PAUSED)) {
- TRACKRENDERER_ERROR_P(this, "Set State to PAUSED failed");
+ TRACKRENDERER_ERROR("Set State to PAUSED failed");
return false;
}
- if (is_pardar_updated_) {
- TRACKRENDERER_INFO_P(this, "is_pardar_updated_ is true");
- pipeline_->SetParDar(Elements::kDecVideo, par_dar_.time_millisecond,
- par_dar_.par_num, par_dar_.par_den, par_dar_.dar_num,
- par_dar_.dar_den);
- }
- audio_lk.unlock();
- if (!HasSubtitleOnly_() &&
- !internal::IsLowLatencyModeDisableAVSync(low_latency_mode_) &&
- !internal::IsLowLatencyModeDisablePreroll(low_latency_mode_))
resource_cv_.wait(lock);
- if (pipeline_) {
- pipeline_->PadRemoveProbe(kPadProbeVideoDecoded);
- }
+
if (state_ != State::kWorking) {
- TRACKRENDERER_ERROR_P(
- this,
+ TRACKRENDERER_ERROR(
"Prepare fail, aborted by eos, error message, resource conflict or "
"stop called");
return false;
}
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
bool TrackRenderer::Pause() {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
if (state_ == State::kStopped) return false;
if (state_ == State::kResourceConflicted) return true;
if (!pipeline_) {
return false;
}
target_substate_ = SubState::kPaused;
- if (!NeedSyncPause_())
- pipeline_->SetState(Elements::kPipeline, GST_STATE_PAUSED);
-
- /*In ChangeSource_ situation, video and audio will in pause status since flush
- event But subtitle can't in pause status since the "async" property is
- false, so need to set to pause alone*/
- GstState cur_state = GST_STATE_NULL;
- bool ret = false;
-
- ret = pipeline_->GetState(Elements::kBinSubtitle, &cur_state, NULL,
- 50 * GST_MSECOND);
- if ((true == ret) && (GST_STATE_PLAYING == cur_state)) {
- TRACKRENDERER_DEBUG_P(
- this, "kBinSubtitle paused failed, try to pause kBinSubtitle alone");
- pipeline_->SetState(Elements::kBinSubtitle, GST_STATE_PAUSED);
- }
-
- ret = pipeline_->GetState(Elements::kSinkCaption, &cur_state, NULL,
- 50 * GST_MSECOND);
- if ((true == ret) && (GST_STATE_PLAYING == cur_state)) {
- TRACKRENDERER_DEBUG_P(
- this, "kSinkCaption paused failed, try to pause kSinkCaption alone");
- pipeline_->SetState(Elements::kSinkCaption, GST_STATE_PAUSED);
- }
-
- TRACKRENDERER_LEAVE_P(this);
+ pipeline_->SetState(Elements::kPipeline, GST_STATE_PAUSED);
+ TRACKRENDERER_LEAVE;
return true;
}
bool TrackRenderer::Resume() {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
if (state_ == State::kStopped) return false;
if (state_ == State::kResourceConflicted) return true;
if (!pipeline_) {
if (is_video_frame_peek_) {
pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
}
- if (support_videodec_underflow_pause_) {
- pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
- }
target_substate_ = SubState::kPlaying;
pipeline_->SetState(Elements::kPipeline, GST_STATE_PLAYING);
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
bool TrackRenderer::SetTrack(const std::vector<Track>& trackinfo) {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
- if (enable_audio_track_change_ && state_ == State::kWorking) {
- enable_audio_track_change_ = false;
-
- if (!internal::IsAvailableCodecChange(*(trackctx_[kTrackTypeAudio].track)))
- return false;
- auto is_audio_track = [](const Track& item) noexcept->bool {
- return item.type == kTrackTypeAudio;
- };
- auto new_track =
- find_if(trackinfo.begin(), trackinfo.end(), is_audio_track);
- if (new_track == trackinfo.end()) return false;
- if (!internal::IsAvailableCodecChange(*new_track)) return false;
-
- auto old_track =
- find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
- if (old_track != trackinfo_.end()) {
- trackinfo_.erase(old_track);
- }
- trackinfo_.push_back(*new_track);
- track_util::ShowTrackInfo(trackinfo_);
- for (auto& track : trackinfo_) {
- if (track.type == kTrackTypeAudio) {
- trackctx_[kTrackTypeAudio].index = track.index;
- trackctx_[kTrackTypeAudio].track = &track;
- auto caps = caps_builder_.Build(
- track,
- internal::IsDrmEmeElementNecessary(drm_property_, track.mimetype));
- pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
- TRACKRENDERER_INFO_P(this, "change audio track after flush");
- }
- }
- return true;
- }
-
if (!trackinfo_.empty()) {
- TRACKRENDERER_ERROR_P(
- this, "trackinfo_ already was set. DO NOT CALL SetTrack()!!");
+ TRACKRENDERER_ERROR("trackinfo_ already was set. DO NOT CALL SetTrack()!!");
return false;
}
trackinfo_ = trackinfo;
- for (auto& track : trackinfo_) {
- if (track.type >= kTrackTypeMax) return false;
+ for (const auto& track : trackinfo_) {
trackctx_[track.type].index = track.index;
trackctx_[track.type].track = &track;
- if (track.type == kTrackTypeVideo) {
- trackctx_[track.type].create_pipeline = std::bind(
- &TrackRenderer::CreateVideoPipeline_, this, std::placeholders::_1);
- UpdateTrackFrameRate_(track.framerate_num, track.framerate_den);
- } else if (track.type == kTrackTypeAudio) {
- if (track.use_swdecoder || internal::IsSdkEnabledFeature()) {
+ LOGD("track.type : %d", track.type);
+ if ((int)track.type == (int)kTrackTypeVideo) {
+ if (internal::IsVideoDecodedBufferNeeded(decoded_buffer_type_))
+ trackctx_[track.type].create_pipeline =
+ std::bind(&TrackRenderer::CreateDecodedVideoPipeline_, this,
+ std::placeholders::_1);
+ else
+ trackctx_[track.type].create_pipeline = std::bind(
+ &TrackRenderer::CreateVideoPipeline_, this, std::placeholders::_1);
+
+ } else if ((int)track.type == (int)kTrackTypeAudio) {
+ if (internal::IsDecoderElementNecessary(track.mimetype)) {
trackctx_[track.type].create_pipeline =
- std::bind(&TrackRenderer::CreateSwAudioPipeline_, this,
+ std::bind(&TrackRenderer::CreateAudioPipeline_, this,
std::placeholders::_1);
} else {
- if (internal::IsDecoderElementNecessary(track.mimetype)) {
- trackctx_[track.type].create_pipeline =
- std::bind(&TrackRenderer::CreateAudioPipeline_, this,
- std::placeholders::_1);
- } else {
- trackctx_[track.type].create_pipeline =
- std::bind(&TrackRenderer::CreateRawAudioPipeline_, this,
- std::placeholders::_1);
- }
+ trackctx_[track.type].create_pipeline =
+ std::bind(&TrackRenderer::CreateRawAudioPipeline_, this,
+ std::placeholders::_1);
}
}
}
}
}
-bool TrackRenderer::Seek(unsigned long long time_millisecond,
+void TrackRenderer::SetIniElement(
+ const std::map<std::string, std::string>& elements) {
+ auto find = [](const std::map<std::string, std::string>& property,
+ const std::string& key, std::string& value) -> bool {
+ auto look = property.find(key);
+ if (look == property.end()) {
+ return false;
+ }
+ value = look->second;
+ return true;
+ };
+ std::string key = "videosink_element_overlay";
+ std::string value = "";
+ if (find(elements, key, value)) {
+ ini_elements_[key] = value;
+ }
+}
+
+bool TrackRenderer::Seek(uint64_t time_millisecond,
double playback_rate) {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
if (state_ == State::kStopped) return false;
if (!pipeline_) {
return false;
}
// mute off/on values are defined in mmaudiosink element
- static const gint mute_off = 2;
- static const gint mute_on = 3;
+ static const int mute_off = 2;
+ static const int mute_on = 3;
+
+ // get user setting
+ bool is_mute = false;
+ pipeline_->GetProperty(Elements::kSinkAudio, "mute", &is_mute);
+
+ int mute_flag = is_mute ? mute_on : mute_off;
- gint mute_flag = mute_off;
gboolean async = TRUE;
if (playback_rate != kDefaultPlaybackRate) {
mute_flag = mute_on;
async = FALSE;
}
- TRACKRENDERER_INFO_P(this, "Set async property as [%d]", async);
- auto is_audio_track = [](const Track& item) noexcept->bool {
+ TRACKRENDERER_INFO("Set async property as [%d]", async);
+ auto is_audio_track = [](Track item) noexcept -> bool {
return item.mimetype.find("audio") != std::string::npos;
};
auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
if (target != trackinfo_.end()) {
- if (target->use_swdecoder || internal::IsSdkEnabledFeature())
- pipeline_->SetProperty(Elements::kSinkAudio, "mute", mute_flag % 2,
- "async", async);
- else {
- pipeline_->SetProperty(Elements::kSinkAudio, "mute-mask", mute_flag,
- "async", async);
- }
+ pipeline_->SetProperty(Elements::kSinkAudio, "mute", mute_flag % 2,
+ "async", async);
}
- TRACKRENDERER_INFO_P(this, " target %llu ms rate [%lf]", time_millisecond,
- playback_rate);
+ TRACKRENDERER_INFO("target %" PRIu64 " ms rate [%lf]", time_millisecond,
+ playback_rate);
gint64 start = time_millisecond * GST_MSECOND, stop = GST_CLOCK_TIME_NONE;
if (playback_rate < 0) {
stop = start;
start = 0;
}
- if (!pipeline_->Seek(playback_rate, GST_FORMAT_TIME,
- (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET,
- start, GST_SEEK_TYPE_SET, stop)) {
- TRACKRENDERER_ERROR_P(this, "Fail to seek to [%llu] ms", time_millisecond);
+
+ int flags = GST_SEEK_FLAG_FLUSH;
+ if (is_accurate_seek_)
+ flags |= GST_SEEK_FLAG_ACCURATE;
+ else
+ flags |= GST_SEEK_FLAG_KEY_UNIT;
+
+ if (!pipeline_->Seek(playback_rate, GST_FORMAT_TIME, (GstSeekFlags)flags,
+ GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop)) {
+ TRACKRENDERER_ERROR("Fail to seek to [%" PRIu64 "] ms", time_millisecond);
}
is_seeking_ = true;
- if (playback_rate != kDefaultPlaybackRate) {
- TRACKRENDERER_INFO_P(this,
- "sequential mode should be off during trickplay");
- pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", TRUE);
- } else
- pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", FALSE);
if (is_video_frame_peek_) {
pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
"sink", GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
GstPadProbeVideoPeekBlockCb_, this, nullptr);
}
- rendering_start_time_.time = start;
if (playback_rate > 0) {
for (int i = 0; i < kTrackTypeMax; ++i) {
trackctx_[i].is_enough_data = false;
trackctx_[i].need_update_segment = true;
}
-
- if (is_accurate_seek_) {
- UpdateStartSegment_(time_millisecond * GST_MSECOND, kTrackTypeMax);
- }
}
playback_rate_ = playback_rate;
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
-bool TrackRenderer::Seek(unsigned long long time_millisecond,
+bool TrackRenderer::Seek(uint64_t time_millisecond,
double playback_rate, bool audio_mute) {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
if (state_ == State::kStopped) return false;
if (!pipeline_) {
return false;
}
// mute off/on values are defined in mmaudiosink element
- static const gint mute_off = 2;
- static const gint mute_on = 3;
+ static const int mute_off = 2;
+ static const int mute_on = 3;
- gint mute_flag = audio_mute ? mute_on : mute_off;
+ int mute_flag = audio_mute ? mute_on : mute_off;
- auto is_audio_track = [](const Track& item) noexcept->bool {
+ auto is_audio_track = [](Track item) noexcept -> bool {
return item.mimetype.find("audio") != std::string::npos;
};
auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
}
}
- TRACKRENDERER_INFO_P(this, " target %llu ms rate [%lf] mute [%d]",
- time_millisecond, playback_rate, audio_mute);
- if (!pipeline_->Seek(playback_rate, GST_FORMAT_TIME,
- (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET,
- time_millisecond * GST_MSECOND, GST_SEEK_TYPE_NONE,
- GST_CLOCK_TIME_NONE)) {
- TRACKRENDERER_ERROR_P(this, "Fail to seek to [%llu] ms", time_millisecond);
+ int flags = GST_SEEK_FLAG_FLUSH;
+ if (is_accurate_seek_)
+ flags |= GST_SEEK_FLAG_ACCURATE;
+ else
+ flags |= GST_SEEK_FLAG_KEY_UNIT;
+
+ TRACKRENDERER_INFO("target %" PRIu64 " ms rate [%lf] mute [%d]", time_millisecond,
+ playback_rate, audio_mute);
+ if (!pipeline_->Seek(playback_rate, GST_FORMAT_TIME, (GstSeekFlags)flags, GST_SEEK_TYPE_SET,
+ time_millisecond * GST_MSECOND, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
+ TRACKRENDERER_ERROR("Fail to seek to [%" PRIu64 "] ms", time_millisecond);
}
is_seeking_ = true;
if (playback_rate != kDefaultPlaybackRate) {
- TRACKRENDERER_INFO_P(this,
- "sequential mode should be off during trickplay");
+ TRACKRENDERER_INFO("sequential mode should be off during trickplay");
pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", TRUE);
} else
pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", FALSE);
"sink", GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
GstPadProbeVideoPeekBlockCb_, this, nullptr);
}
- if (support_videodec_underflow_pause_) {
- pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
- }
- rendering_start_time_.time = time_millisecond * GST_MSECOND;
for (int i = 0; i < kTrackTypeMax; ++i) {
trackctx_[i].is_enough_data = false;
trackctx_[i].need_update_segment = true;
}
-
- if (is_accurate_seek_) {
- UpdateStartSegment_(time_millisecond * GST_MSECOND, kTrackTypeMax);
- }
playback_rate_ = playback_rate;
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
bool TrackRenderer::SetPlaybackRate(double playback_rate, bool audio_mute) {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
if (state_ == State::kStopped) return false;
if (!pipeline_) {
return false;
}
// mute off/on values are defined in mmaudiosink element
- static const gint mute_off = 2;
- static const gint mute_on = 3;
- uint64_t curtime_in_msec = 0;
- gint mute_flag = audio_mute ? mute_on : mute_off;
+ static const int mute_off = 2;
+ static const int mute_on = 3;
+ uint64_t last_video_pts = 0, curtime_in_msec = 0;
+ int mute_flag = audio_mute ? mute_on : mute_off;
GetPlayingTime_(&curtime_in_msec);
- TRACKRENDERER_INFO_P(this, "Set mute-mask property as [%d] ,rate [%lf]",
- mute_flag, playback_rate);
- auto is_audio_track = [](const Track& item) noexcept->bool {
+ TRACKRENDERER_INFO("Set mute-mask property as [%d] ,rate [%lf]", mute_flag,
+ playback_rate);
+ auto is_audio_track = [](Track item) noexcept -> bool {
return item.mimetype.find("audio") != std::string::npos;
};
auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
gint(playback_rate * 100));
}
}
-
- Elements audio_probe_element = Elements::kDecAudio;
- Elements video_probe_element = Elements::kDecVideo;
- Elements subtitle_probe_element = Elements::kAppSrcSubtitle;
- Elements close_caption_probe_element = Elements::kQueueCaption;
- for (const Track& track : trackinfo_) {
- if (internal::IsPcmMimeType(track.mimetype)) {
- audio_probe_element = Elements::kAppSrcAudio;
- } else if (internal::IsVideoRawMimeType(track.mimetype)) {
- video_probe_element = Elements::kAppSrcVideo;
- }
- }
- std::map<Elements, std::pair<std::string, std::string>> probe_map = {
- {audio_probe_element,
- {"AUDIO_RATE_IDLE_PROBE", "AUDIO_RATE_BLOCK_PROBE"}},
- {video_probe_element,
- {"VIDEO_RATE_IDLE_PROBE", "VIDEO_RATE_BLOCK_PROBE"}},
- {subtitle_probe_element,
- {"SUBTITLE_RATE_IDLE_PROBE", "SUBTITLE_RATE_BLOCK_PROBE"}},
- {close_caption_probe_element,
- {"CLOSE_CAPTION_RATE_IDLE_PROBE", "CLOSE_CAPTION_RATE_BLOCK_PROBE"}}};
-
- std::map<Elements, Elements> probe_sink_map = {
- {audio_probe_element, Elements::kSinkAudio},
- {video_probe_element, Elements::kSinkVideo},
- {subtitle_probe_element, Elements::kSinkSubtitle},
- {close_caption_probe_element, Elements::kSinkCaption}};
-
- for (auto& kv : probe_map) {
- const Elements& element = kv.first;
- std::pair<std::string, std::string>& probe = kv.second;
- pipeline_->PadAddProbe(element, (probe.second).c_str(), "src",
- GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, nullptr,
- nullptr, nullptr);
- gboolean is_sync = FALSE;
- pipeline_->GetProperty(probe_sink_map[element], "sync", &is_sync);
- pipeline_->SetProperty(probe_sink_map[element], "sync", FALSE);
- FlushDownStream_(element, (probe.first).c_str(), TRUE);
- if (is_sync) pipeline_->SetProperty(probe_sink_map[element], "sync", TRUE);
+ if (!pipeline_->Seek(
+ playback_rate, GST_FORMAT_TIME,
+ (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
+ GST_SEEK_TYPE_SET, curtime_in_msec * GST_MSECOND, GST_SEEK_TYPE_NONE,
+ GST_CLOCK_TIME_NONE)) {
+ TRACKRENDERER_ERROR("Fail to seek ");
}
-
if (playback_rate != kDefaultPlaybackRate) {
- TRACKRENDERER_INFO_P(this,
- "sequential mode should be off during trickplay");
+ TRACKRENDERER_INFO("sequential mode should be off during trickplay");
pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", TRUE);
} else
pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", FALSE);
- for (auto& kv : probe_map) {
- const Elements& element = kv.first;
- std::pair<std::string, std::string>& probe = kv.second;
- pipeline_->PushSegmentEvent(element, curtime_in_msec * GST_MSECOND,
- playback_rate);
- pipeline_->PadRemoveProbe((probe.second).c_str());
+ pipeline_->GetProperty(Elements::kSinkVideo, "last-video-pts",
+ &last_video_pts);
+ if (last_video_pts > 0) {
+ pipeline_->SetProperty(Elements::kAppSrcVideo, "update-segment",
+ last_video_pts);
+ pipeline_->SetProperty(Elements::kAppSrcAudio, "update-segment",
+ last_video_pts);
+ pipeline_->SetProperty(Elements::kAppSrcSubtitle, "update-segment",
+ last_video_pts);
}
- rendering_start_time_.time = curtime_in_msec * GST_MSECOND;
playback_rate_ = playback_rate;
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
-// LCOV_EXCL_START
bool TrackRenderer::ControlDropRate_(uint64_t packet_pts,
SubmitStatus* status) {
uint64_t current_time = 0;
GetPlayingTime_(¤t_time);
- const auto islate = [](uint64_t cur_time, uint64_t pts) {
+ //constexpr auto islate = [](uint64_t cur_time, uint64_t pts) {
+ auto islate = [](uint64_t cur_time, uint64_t pts) {
if (pts <= cur_time) {
return true;
} else {
return false;
}
-bool TrackRenderer::IsSegmentUpdated_() const {
- for (int i = 0; i < kTrackTypeMax; i++) {
- if (trackctx_[i].need_update_segment == false) return true;
- }
- return false;
-}
-
bool TrackRenderer::HasSubtitleOnly_() const {
return trackctx_[kTrackTypeAudio].index == kInvalidTrackIndex &&
trackctx_[kTrackTypeVideo].index == kInvalidTrackIndex &&
trackctx_[kTrackTypeSubtitle].index != kInvalidTrackIndex;
}
-// LCOV_EXCL_STOP
bool TrackRenderer::SubmitPacket(const DecoderInputBufferPtr& data,
SubmitStatus* status) {
submitstate = SubmitStatus::kNotPrepared;
return false;
}
+
if (!pipeline_) {
- // TRACKRENDERER_DEBUG_P(this, "pipeline is nullptr , wait prepared");
+ TRACKRENDERER_DEBUG("pipeline is nullptr , wait prepared");
submitstate = SubmitStatus::kNotPrepared;
return false;
}
return true;
}
- // TRACKRENDERER_DEBUG_P(this,
- // "TYPE[%d] PKT INDEX[%d] TIMESTAMP[%lld]ms SIZE[%d] EOS[%d]", type,
- // data->GetIndex(), GST_BUFFER_TIMESTAMP(data->Get()) / 1000000,
- // gst_buffer_get_size(const_cast<GstBuffer*>(data->Get())),
- // data->IsEos());
-
- if (type >= kTrackTypeMax) return false;
- if (trackctx_[type].index == kInvalidTrackIndex) {
- // TRACKRENDERER_ERROR_P(this, "data is not activated track. type:%d,
- // input:acti %d:%d", type, data->GetIndex(), trackctx_[type].index);
+ if (trackctx_[type].index == kInvalidTrackIndex // Track is not activated.
+ || data->GetIndex() != trackctx_[type].index) {
+ TRACKRENDERER_DEBUG("ControlDropRate [%d] %d vs %d", type, data->GetIndex(), trackctx_[type].index);
return ControlDropRate_(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(data->Get())),
&submitstate);
}
return false;
}
- const bool is_segment_updated = IsSegmentUpdated_();
- const bool request_to_hold_subtitle = (type == kTrackTypeSubtitle) &&
- (is_segment_updated == false) &&
- (HasSubtitleOnly_() == false);
-
- if (request_to_hold_subtitle) {
- TRACKRENDERER_INFO_P(this, "subtitle should be submitted after a/v packet");
- submitstate = SubmitStatus::kHold;
- return false;
+ const GstCaps *caps = data->GetCaps();
+ if (caps) {
+ /* FIXME : need to check whether the caps need to be updated or not */
+ pipeline_->SetAppSrcCaps(element, caps);
}
GstBuffer* buffer = data->Release();
-
- if (is_segment_updated == false) {
- UpdateStartSegment_(GST_BUFFER_TIMESTAMP(buffer), type);
- }
+ if (start_time == -1 && type != kTrackTypeSubtitle)
+ start_time = GST_BUFFER_TIMESTAMP(buffer);
pipeline_->AppSrcPushBuffer(element, buffer);
-
- if (type == kTrackTypeVideo) {
- latency_manager_->UpdateVideoFrameStatus(
- LatencyManager::UpdatePacketStatus::kSubmit);
- }
-
submitstate = SubmitStatus::kSuccess;
return true;
}
+TrackType TrackRenderer::GetBaseTrackType_() {
+ TrackType type = kTrackTypeSubtitle;
+ if (trackctx_[kTrackTypeVideo].index != kInvalidTrackIndex)
+ type = kTrackTypeVideo;
+ else if (trackctx_[kTrackTypeAudio].index != kInvalidTrackIndex)
+ type = kTrackTypeAudio;
+ return type;
+}
+
bool TrackRenderer::SetMatroskaColorInfo(const std::string& color_info) {
- TRACKRENDERER_ENTER_P(this);
- std::lock_guard<std::mutex> lk(resource_m_);
+ TRACKRENDERER_ENTER;
+ std::unique_lock<std::mutex> lock(resource_m_);
if (state_ == State::kStopped) return false;
if (pipeline_ == nullptr) return false;
GstCaps* old_caps = nullptr;
return true;
}
-void TrackRenderer::UpdateStartSegment_(GstClockTime start_time,
- const TrackType& type) {
- if (type == kTrackTypeMax) {
- TRACKRENDERER_INFO_P(
- this, "update src segment with start time [%llu ms] for all tracks",
- start_time / 1000000);
- for (int i = 0; i < kTrackTypeMax; ++i) {
- trackctx_[i].need_update_segment = false;
- }
- } else {
- const auto& track_type_str = track_util::GetTrackTypeString(type);
- TRACKRENDERER_ERROR_P(
- this, "update src segment with first pts [%llu ms] by %s stream",
- start_time / 1000000, track_type_str.c_str());
- trackctx_[type].need_update_segment = false;
- }
-
- if (rendering_start_time_.is_set) {
- start_time = rendering_start_time_.time;
- rendering_start_time_.is_set = false;
- TRACKRENDERER_ERROR_P(
- this,
- "update src segment with first pts [%llu ms] by start-rendering-time",
- start_time / 1000000);
- }
-
- pipeline_->SetProperty(Elements::kAppSrcVideo, "update-segment", start_time);
- pipeline_->SetProperty(Elements::kAppSrcAudio, "update-segment", start_time);
- pipeline_->SetProperty(Elements::kAppSrcSubtitle, "update-segment",
- start_time);
- rendering_start_time_.time = start_time;
-}
-
void TrackRenderer::CreateAppSrc_(TrackType type, const std::string& mimetype) {
+ TRACKRENDERER_ENTER;
if (internal::IsTzAppSrcElementNecessary(drm_property_, mimetype)) {
if (type == kTrackTypeVideo) {
pipeline_->FactoryMake(Elements::kAppSrcVideo, "tzappsrc",
} else {
if (type == kTrackTypeVideo) {
pipeline_->FactoryMake(Elements::kAppSrcVideo, "appsrc", "video_appsrc");
+ pipeline_->PadAddProbe(Elements::kAppSrcVideo, kPadProbeAppsrcEvent, "src",
+ (GstPadProbeType)(GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM),
+ GstPadProbeAppsrcEventCb_, this, nullptr);
} else {
pipeline_->FactoryMake(Elements::kAppSrcAudio, "appsrc", "audio_appsrc");
+ pipeline_->PadAddProbe(Elements::kAppSrcAudio, kPadProbeAppsrcEvent, "src",
+ (GstPadProbeType)(GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM),
+ GstPadProbeAppsrcEventCb_, this, nullptr);
}
}
- SetDefaultAppSrcSignals_(type);
+ TRACKRENDERER_LEAVE;
+}
- Elements element = Elements::kAppSrcAudio;
- if (type == kTrackTypeVideo) element = Elements::kAppSrcVideo;
+bool TrackRenderer::CreateVideoPipeline_(const Track* track) {
+ TRACKRENDERER_ENTER;
- pipeline_->SetProperty(element, "format", GST_FORMAT_TIME);
- pipeline_->SetProperty(element, "stream-type", GST_APP_STREAM_TYPE_SEEKABLE);
-}
+ CreateAppSrc_(kTrackTypeVideo, track->mimetype);
+ auto caps = caps_builder_.Build(*track, internal::IsDrmEmeElementNecessary(
+ drm_property_, track->mimetype));
+ if (internal::IsDecryptorElementNecessary(drm_property_)) {
+ auto caps_for_parser = caps_builder_.BuildOrgMediaType(*track, internal::IsDrmEmeElementNecessary(
+ drm_property_, track->mimetype));
+ pipeline_->FactoryMake(Elements::kParseVideo, (GstCaps*)caps_for_parser.GetCaps_(),
+ GST_ELEMENT_FACTORY_TYPE_PARSER, NULL);
+ } else {
+ pipeline_->FactoryMake(Elements::kParseVideo, (GstCaps*)caps.GetCaps_(),
+ GST_ELEMENT_FACTORY_TYPE_PARSER, NULL);
+ }
-void TrackRenderer::SetDefaultAppSrcSignals_(const TrackType& type) {
- if (type == kTrackTypeVideo) {
- pipeline_->SignalConnect(Elements::kAppSrcVideo, "need-data",
- G_CALLBACK(GstVideoNeedDataCb_), this);
- pipeline_->SignalConnect(Elements::kAppSrcVideo, "enough-data",
- G_CALLBACK(GstVideoEnoughDataCb_), this);
- pipeline_->SignalConnect(Elements::kAppSrcVideo, "seek-data",
- G_CALLBACK(GstVideoSeekDataCb_), this);
- } else if (type == kTrackTypeAudio) {
- pipeline_->SignalConnect(Elements::kAppSrcAudio, "need-data",
- G_CALLBACK(GstAudioNeedDataCb_), this);
- pipeline_->SignalConnect(Elements::kAppSrcAudio, "enough-data",
- G_CALLBACK(GstAudioEnoughDataCb_), this);
- pipeline_->SignalConnect(Elements::kAppSrcAudio, "seek-data",
- G_CALLBACK(GstAudioSeekDataCb_), this);
- } else if (type == kTrackTypeSubtitle) {
- pipeline_->SignalConnect(Elements::kAppSrcSubtitle, "need-data",
- G_CALLBACK(GstSubtitleNeedDataCb_), this);
- pipeline_->SignalConnect(Elements::kAppSrcSubtitle, "enough-data",
- G_CALLBACK(GstSubtitleEnoughDataCb_), this);
- pipeline_->SignalConnect(Elements::kAppSrcSubtitle, "seek-data",
- G_CALLBACK(GstSubtitleSeekDataCb_), this);
+ auto parse_caps =
+ gstguard::make_guard(pipeline_->GetSrcPadCaps(Elements::kParseVideo));
+
+ if (!pipeline_->FactoryMake(Elements::kDecVideo, (GstCaps*)parse_caps.get(),
+ GST_ELEMENT_FACTORY_TYPE_DECODER, NULL)) {
+ const ErrorType err = ErrorType::kNotSupportedVideoCodec;
+ eventlistener_->OnError(err);
+ return false;
}
-}
-void TrackRenderer::CreateDrmElement_(const Track& track) {
- if (!internal::IsDrmEmeElementNecessary(drm_property_, track.mimetype))
- return;
+ pipeline_->FactoryMake(Elements::kSinkVideo,
+ internal::GetVideoSinkPluginName(ini_elements_, track->use_swdecoder), NULL);
- if (track.type == kTrackTypeAudio) {
- pipeline_->FactoryMake(Elements::kDrmAudio, "drm_eme", "audio_drm");
- pipeline_->SetProperty(Elements::kDrmAudio, "plus-player-eme", TRUE);
- if (internal::IsExternalDecryptionCase(drm_property_) == false) {
- pipeline_->SetProperty(Elements::kDrmAudio, "getrights-complete-cb",
- GstAudioDrmInitDataCb_);
- pipeline_->SetProperty(Elements::kDrmAudio, "getrights-complete-cb-data",
- this);
- }
- } else if (track.type == kTrackTypeVideo) {
+ pipeline_->FactoryMake(Elements::kCCExtractor, "ccextractor", "ccextractor");
+
+ pipeline_->CreateBin(Elements::kBinVideo, "videobin");
+
+ pipeline_->SignalConnect(Elements::kCCExtractor, "pad-added",
+ G_CALLBACK(GstClosedCaptionPadAddedCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcVideo, "need-data",
+ G_CALLBACK(GstVideoNeedDataCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcVideo, "enough-data",
+ G_CALLBACK(GstVideoEnoughDataCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcVideo, "seek-data",
+ G_CALLBACK(GstVideoSeekDataCb_), this);
+ pipeline_->SetProperty(Elements::kAppSrcVideo, "format", GST_FORMAT_TIME);
+
+ // TODO: need to implement drmdecryptor plugin
+ // FIXME: drm plugin should be added before parser
+ if (internal::IsDecryptorElementNecessary(drm_property_)) {
+ pipeline_->FactoryMake(Elements::kDrmVideo, "cencdecrypt", NULL);
+ pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-cb",
+ GstVideoDrmInitDataCb_);
+ pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-cb-data",
+ this);
+ if (pipeline_->IsFactoryListType(Elements::kDecVideo, GST_ELEMENT_FACTORY_TYPE_HARDWARE)) {
+ pipeline_->SetProperty(Elements::kSinkVideo, "use-tbm", true);
+ pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo, Elements::kDrmVideo,
+ Elements::kParseVideo, Elements::kDecVideo, Elements::kCCExtractor, Elements::kSinkVideo);
+ } else { /* sw */
+ pipeline_->FactoryMake(Elements::kVideoConvert, "videoconvert", NULL);
+ pipeline_->SetProperty(Elements::kSinkVideo, "use-tbm", false);
+ pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo, Elements::kDrmVideo,
+ Elements::kParseVideo, Elements::kDecVideo, Elements::kCCExtractor, Elements::kVideoConvert,
+ Elements::kSinkVideo);
+ }
+ } else if (internal::IsDrmEmeElementNecessary(drm_property_, track->mimetype)) {
pipeline_->FactoryMake(Elements::kDrmVideo, "drm_eme", "video_drm");
pipeline_->SetProperty(Elements::kDrmVideo, "plus-player-eme", TRUE);
if (!internal::IsExternalDecryptionCase(drm_property_)) {
pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-cb-data",
this);
}
- }
-}
-const char* TrackRenderer::GetAudioSinkPluginName_(
- bool swdecoder, const std::string& mimetype) {
- if (internal::IsSdkEnabledFeature()) return "pulsesink";
- if (product_cfg::GetProductType() == ProductType::kAv) {
- return "mmaudiosink2";
- }
- if (swdecoder || internal::IsPcmMimeType(mimetype)) {
- const std::string comp_name =
- resource_manager_->GetComponentName(audio_out_id_);
- if (comp_name == kPulseSinkComponentName) return "pulsesink";
- return ::SinkPluginTable.count(::DeviceSinkElementType::kPcmAudiosink) > 0
- ? ::SinkPluginTable.at(::DeviceSinkElementType::kPcmAudiosink)
- .c_str()
- : nullptr;
- }
- return ::SinkPluginTable.count(::DeviceSinkElementType::kAudioSink) > 0
- ? ::SinkPluginTable.at(::DeviceSinkElementType::kAudioSink).c_str()
- : nullptr;
-}
-
-void TrackRenderer::CreateAudioSink_(const std::string& sink_name) {
- if (sink_name.find("alsasink") != std::string::npos ||
- sink_name.find("pulsesink") != std::string::npos) {
- pipeline_->FactoryMake(Elements::kAudioConvert, "audioconvert", nullptr);
- pipeline_->FactoryMake(Elements::kCapsFillterDefault, "capsfilter",
- nullptr);
- auto caps1 = gstguard::make_guard(
- gst_caps_from_string("audio/x-raw, "
- "format = (string) S16LE, "
- "layout = (string) interleaved, "
- "channels = (int) 2"));
- pipeline_->SetProperty(Elements::kCapsFillterDefault, "caps", caps1.get());
- pipeline_->FactoryMake(Elements::kAudioResample, "audioresample", nullptr);
- pipeline_->FactoryMake(Elements::kCapsFillter2, "capsfilter", nullptr);
- auto caps2 =
- gstguard::make_guard(gst_caps_from_string("audio/x-raw, "
- "rate = (int) 48000"));
- pipeline_->SetProperty(Elements::kCapsFillter2, "caps", caps2.get());
- pipeline_->FactoryMake(Elements::kScaleTempo, "scaletempo", nullptr);
-
- pipeline_->FactoryMake(Elements::kSinkAudio, sink_name.c_str(), NULL);
- if (sink_name.find("pulsesink") == std::string::npos) {
- pipeline_->SetProperty(Elements::kSinkAudio, "device", "hw:0,0");
- }
- pipeline_->SetProperty(Elements::kSinkAudio, "drift-tolerance",
- ((200 * GST_MSECOND) / GST_USECOND));
- pipeline_->SetProperty(Elements::kSinkAudio, "provide-clock", FALSE);
- pipeline_->SetProperty(Elements::kSinkAudio, "sync", TRUE);
- pipeline_->SetProperty(Elements::kSinkAudio, "force-render", FALSE);
- pipeline_->SetProperty(Elements::kSinkAudio, "multiview-window-id",
- static_cast<int>(display_->GetSurfaceId()));
-
- if (sink_name.find("pulsesink") == std::string::npos) {
- resync_audio_policy_.reset(new resync_audio::DummyPolicy());
- } else {
- resync_audio_policy_.reset(new resync_audio::SwDecoderPolicy(
- rendering_start_time_.time, playback_rate_));
- }
- } else if (sink_name.find("fakesink") != std::string::npos) {
- TRACKRENDERER_ERROR_P(this, "fake");
- pipeline_->FactoryMake(Elements::kSinkAudio, sink_name.c_str(), NULL);
- pipeline_->SetProperty(Elements::kSinkAudio, "async", TRUE, NULL);
- pipeline_->SetProperty(Elements::kSinkAudio, "sync", TRUE, NULL);
- pipeline_->SetProperty(Elements::kSinkAudio, "max-lateness",
- static_cast<gint64>(-1), NULL);
- pipeline_->SetProperty(Elements::kSinkAudio, "no-drop", TRUE, NULL);
- resync_audio_policy_.reset(new resync_audio::DummyPolicy());
+ pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo,
+ Elements::kDrmVideo, Elements::kDecVideo, Elements::kCCExtractor,
+ Elements::kSinkVideo);
} else {
- pipeline_->FactoryMake(Elements::kSinkAudio, sink_name.c_str(), NULL);
- pipeline_->SetProperty(Elements::kSinkAudio, //
- "sync", TRUE, //
- "async", TRUE, //
- "fast-rendering", 200000000LL, //
- "force-render", FALSE);
- pipeline_->SetProperty(Elements::kSinkAudio, "multiview-window-id",
- static_cast<int>(display_->GetSurfaceId()));
- int is_audio_decoder_sub =
- resource_manager_->IsMainDevice(audio_decoder_id_) ? 0 : 1;
- pipeline_->SetProperty(Elements::kSinkAudio, "device-audio-decoder",
- is_audio_decoder_sub, NULL);
- resync_audio_policy_.reset(new resync_audio::DefaultPolicy());
- }
- pipeline_->SetProperty(Elements::kSinkAudio, "mls-player-id", avoc_id_);
-}
-
-void TrackRenderer::CreateVideoDecoder_(const char* dec_name) {
- pipeline_->FactoryMake(Elements::kDecVideo, dec_name, NULL);
-
- pipeline_->SetProperty(Elements::kDecVideo, "extradata_flag", TRUE);
- pipeline_->SetProperty(Elements::kDecVideo, "decoding-type",
- static_cast<gint>(video_decoding_mode_));
- pipeline_->SignalConnect(Elements::kDecVideo, "pad-added",
- G_CALLBACK(GstClosedCaptionPadAddedCb_), this);
-}
+ if (pipeline_->IsFactoryListType(Elements::kDecVideo, GST_ELEMENT_FACTORY_TYPE_HARDWARE)) {
+ pipeline_->SetProperty(Elements::kSinkVideo, "use-tbm", true);
+ pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo, Elements::kParseVideo,
+ Elements::kDecVideo, Elements::kCCExtractor, Elements::kSinkVideo);
-bool TrackRenderer::CreateVideoSink_() {
- if (internal::IsDisplayNeeded(display_type_) == false)
- pipeline_->FactoryMake(Elements::kSinkVideo, "fakesink", "fakesink");
- else
- pipeline_->FactoryMake(Elements::kSinkVideo, "directvideosink",
- "directvideosink");
-
- // gstbasesink property
- pipeline_->SetProperty(Elements::kSinkVideo, "sync", TRUE, "async", TRUE,
- "max-lateness", static_cast<gint64>(0));
- if (video_pre_display_mode_)
- pipeline_->SetProperty(Elements::kSinkVideo, "accurate-resume", TRUE);
- if (drop_all_late_video_)
- pipeline_->SetProperty(Elements::kSinkVideo, "force-render", FALSE);
-
- if (internal::IsDisplayNeeded(display_type_) == false) return true;
-
- // gstwaylandsink property
- pipeline_->SetProperty(Elements::kSinkVideo, "subsurface-stand-alone",
- window_stand_alone_mode_);
- SetSequentialMode_();
- pipeline_->SetProperty(Elements::kSinkVideo, "use-seq-mode", use_seq_mode_);
- virtual_scaler_id_ = resource_manager_->GetDeviceId(video_renderer_id_);
- if (virtual_scaler_id_ == -1) {
- return false;
+ } else { /* sw */
+ pipeline_->FactoryMake(Elements::kVideoQueue, "queue", NULL);
+ pipeline_->SetProperty(Elements::kVideoQueue, "max-size-buffers", 2);
+
+ pipeline_->FactoryMake(Elements::kVideoConvert, "videoconvert", NULL);
+ pipeline_->SetProperty(Elements::kVideoConvert, "n-threads", 2);
+
+ pipeline_->SetProperty(Elements::kSinkVideo, "use-tbm", false);
+ pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo, Elements::kParseVideo,
+ Elements::kDecVideo, Elements::kCCExtractor, Elements::kVideoQueue, Elements::kVideoConvert, Elements::kSinkVideo);
+ }
}
- pipeline_->SetProperty(Elements::kSinkVideo, "device-scaler",
- virtual_scaler_id_);
-
- if (fmm_mode_)
- pipeline_->SetProperty(Elements::kSinkVideo, "fmm-mode", fmm_mode_);
- if (enable_direct_crop_)
- pipeline_->SetProperty(Elements::kSinkVideo, "enable-direct-crop", TRUE);
-#ifndef SOUNDBAR_PRODUCT
- if (avoc_sub_source_ != AVOC_SUB_SOURCE_NONE)
- pipeline_->SetProperty(Elements::kSinkVideo, "avoc-sub-source",
- static_cast<gint>(avoc_sub_source_));
-#endif
+
+ pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinVideo);
+
+ pipeline_->SetAppSrcCaps(Elements::kAppSrcVideo, caps);
+
+ pipeline_->SetProperty(Elements::kAppSrcVideo, "stream-type",
+ GST_APP_STREAM_TYPE_SEEKABLE);
+
+ TRACKRENDERER_LEAVE;
return true;
}
-void TrackRenderer::SetPropertyForAiFilter_() {
- if (aifilter_ == nullptr) return;
- pipeline_->ElementAdd(Elements::kAiFilter, aifilter_);
- pipeline_->SetProperty(Elements::kAiFilter, "scaler-id", virtual_scaler_id_);
- pipeline_->SignalConnect(Elements::kAiFilter, "return-result",
- G_CALLBACK(GstAiFilterResultCb_), this);
- return;
-}
+bool TrackRenderer::CreateDecodedVideoPipeline_(const Track* track) {
+ TRACKRENDERER_ENTER;
+ CreateTbmBufferManager_(track);
+ auto caps = caps_builder_.Build(*track, internal::IsDrmEmeElementNecessary(
+ drm_property_, track->mimetype));
-void TrackRenderer::SetPropertyForDecodedVideoBufferWithDisplay_() {
- if (pipeline_ == nullptr) return;
- if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kScale) {
- pipeline_->SignalConnect(Elements::kDecVideo, "get-buffer",
- G_CALLBACK(GstDecodedVideoScaleBufferCb_), this);
- pipeline_->SetProperty(Elements::kDecVideo, "signal-outbuffer", TRUE);
+ CreateAppSrc_(kTrackTypeVideo, track->mimetype);
+ if (!pipeline_->FactoryMake(Elements::kDecVideo, (GstCaps*)caps.GetCaps_(),
+ GST_ELEMENT_FACTORY_TYPE_DECODER, NULL)) {
+ const ErrorType err = ErrorType::kNotSupportedVideoCodec;
+ eventlistener_->OnError(err);
+ return false;
}
- return;
-}
-void TrackRenderer::SetPropertyForDecodedVideoBufferWithoutDisplay_() {
- /*in case of omx seamless mode,if not render omx data directly,like copy
- * omxdata to DP buffer case,need set bNoVideoOut= True .*/
- if (pipeline_ == nullptr) return;
+ pipeline_->FactoryMake(Elements::kSinkVideo, "fakesink", "fakesink");
+ if (video_pre_display_mode_) {
+ pipeline_->SetProperty(Elements::kSinkVideo, "accurate-resume", 1);
+ }
+
+ pipeline_->CreateBin(Elements::kBinVideo, "videobin");
+
+ pipeline_->SignalConnect(Elements::kAppSrcVideo, "need-data",
+ G_CALLBACK(GstVideoNeedDataCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcVideo, "enough-data",
+ G_CALLBACK(GstVideoEnoughDataCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcVideo, "seek-data",
+ G_CALLBACK(GstVideoSeekDataCb_), this);
+ pipeline_->SetProperty(Elements::kAppSrcVideo, "format", GST_FORMAT_TIME);
+
+ if (internal::IsDrmEmeElementNecessary(drm_property_, track->mimetype)) {
+ pipeline_->FactoryMake(Elements::kDrmVideo, "drm_eme", "video_drm");
+ pipeline_->SetProperty(Elements::kDrmVideo, "plus-player-eme", TRUE);
+ if (internal::IsExternalDecryptionCase(drm_property_) == false) {
+ pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-cb",
+ GstVideoDrmInitDataCb_);
+ pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-cb-data",
+ this);
+ }
+
+ pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo,
+ Elements::kDrmVideo, Elements::kDecVideo,
+ Elements::kSinkVideo);
+ } else {
+ pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo,
+ Elements::kDecVideo, Elements::kSinkVideo);
+ }
+
+ pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinVideo);
+ pipeline_->SetAppSrcCaps(Elements::kAppSrcVideo, caps);
+
+ pipeline_->SetProperty(Elements::kAppSrcVideo, "stream-type",
+ GST_APP_STREAM_TYPE_SEEKABLE);
+
+ /*in case of omx seamless mode,if not render omx data directly,like copy
+ * omxdata to DP buffer case,need set bNoVideoOut= True .Guide from
+ * taing.kim@samsung.com,min.byun@samsung.com*/
pipeline_->SetProperty(Elements::kDecVideo, "display-omxdata-direct", FALSE);
- TRACKRENDERER_INFO_P(
- this,
+ TRACKRENDERER_INFO(
"set [ %d ] to 'display-omxdata-direct' property of omx seamless "
"videodec",
FALSE);
pipeline_->SignalConnect(Elements::kSinkVideo, "handoff",
G_CALLBACK(GstDecodedVideoReferenceBufferCb_),
this);
- } else if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kRaw) {
- constexpr int kTbmBoType =
- 0; // 1:tbm bo, 0:CMA (refer to gstffmpegdec element, currently for
- // this feature use only sw decoder(ffmpegdec) and tbm_bo)
- pipeline_->SetProperty(Elements::kDecVideo, "tbm-buffer-type", kTbmBoType);
- pipeline_->SignalConnect(Elements::kSinkVideo, "handoff",
- G_CALLBACK(GstDecodedVideoRawBufferCb_), this);
- } else if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kScale) {
- pipeline_->SignalConnect(Elements::kDecVideo, "get-buffer",
- G_CALLBACK(GstDecodedVideoScaleBufferCb_), this);
- pipeline_->SetProperty(Elements::kDecVideo, "signal-outbuffer", TRUE);
- pipeline_->SetProperty(Elements::kSinkVideo, "signal-handoffs", FALSE);
- }
- return;
-}
-
-void TrackRenderer::SetPropertyForDecodedVideoBuffer_() {
- if (internal::IsDecodedVideoBufferNeeded(decoded_buffer_type_) == false)
- return;
-
- CreateTbmBufferManager_();
-
- if (internal::IsDisplayNeeded(display_type_))
- SetPropertyForDecodedVideoBufferWithDisplay_();
- else
- SetPropertyForDecodedVideoBufferWithoutDisplay_();
- return;
-}
-
-bool TrackRenderer::CreateVideoPipeline_(const Track* track) {
- const char* kDecoderPluginName =
- GetDecoderPluginName_(kTrackTypeVideo, track->mimetype);
- if (kDecoderPluginName == nullptr &&
- internal::IsDecoderElementNecessary(track->mimetype)) {
- const ErrorType err = ErrorType::kNotSupportedVideoCodec;
- eventlistener_->OnError(err);
- eventlistener_->OnErrorMsg(err, const_cast<char*>(track->mimetype.c_str()));
- return false;
- }
- if (kDecoderPluginName &&
- (strcmp(kDecoderPluginName, kSkippedResource) == 0)) {
- const ErrorType err = ErrorType::kResourceLimit;
- eventlistener_->OnError(err);
- eventlistener_->OnErrorMsg(err, const_cast<char*>(track->mimetype.c_str()));
- return false;
}
- CreateAppSrc_(kTrackTypeVideo, track->mimetype);
-
- CreateDrmElement_(*track);
-
- CreateVideoDecoder_(kDecoderPluginName);
-
- if (CreateVideoSink_() == false) return false;
-
- GstElementLowLatency_(kTrackTypeVideo);
-
- SetPropertyForAiFilter_();
-
- pipeline_->CreateBin(Elements::kBinVideo, "videobin");
-
- pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo,
- Elements::kDrmVideo, Elements::kDecVideo,
- Elements::kAiFilter, Elements::kSinkVideo);
-
- pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinVideo);
- auto caps = caps_builder_.Build(*track, internal::IsDrmEmeElementNecessary(
- drm_property_, track->mimetype));
- pipeline_->SetAppSrcCaps(Elements::kAppSrcVideo, caps);
+ pipeline_->SetProperty(Elements::kSinkVideo, "sync", TRUE, "async", TRUE);
- if (is_video_frame_peek_) {
- pipeline_->PadAddProbe(Elements::kSinkVideo, kPadProbeVideoDecoded, "sink",
- GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
- GstPadProbeVideoDecodedCb_, this, nullptr);
- }
- SetPropertyForDecodedVideoBuffer_();
+ TRACKRENDERER_LEAVE;
return true;
}
bool TrackRenderer::CreateAudioPipeline_(const Track* track) {
- const char* kDecoderPluginName =
- GetDecoderPluginName_(kTrackTypeAudio, track->mimetype);
- if (kDecoderPluginName == nullptr) {
- const ErrorType err = ErrorType::kNotSupportedAudioCodec;
- eventlistener_->OnError(err);
- eventlistener_->OnErrorMsg(err, const_cast<char*>(track->mimetype.c_str()));
- return false;
- }
- pipeline_->CreateBin(Elements::kBinAudio, "audiobin");
+ TRACKRENDERER_ENTER;
CreateAppSrc_(kTrackTypeAudio, track->mimetype);
- auto caps = caps_builder_.Build(*track, internal::IsDrmEmeElementNecessary(
- drm_property_, track->mimetype));
- pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
-
- CreateDrmElement_(*track);
-
- if (strcmp(kDecoderPluginName, kSkippedResource) != 0) {
- pipeline_->FactoryMake(Elements::kDecAudio, kDecoderPluginName, NULL);
- pipeline_->SetProperty(Elements::kDecAudio, "support-codec-change",
- support_audio_codec_change_);
- if (low_latency_mode_ ==
- static_cast<std::uint32_t>(LowLatencyMode::kLowLatencyModeNone)) {
- constexpr int kPtsManipulationThreshold = 99000; // 99ms
- pipeline_->SetProperty(Elements::kDecAudio, "set-usr-cal-timestamp",
- kPtsManipulationThreshold);
- }
- std::string audiosink_name =
- GetAudioSinkPluginName_(track->use_swdecoder, track->mimetype);
- CreateAudioSink_(audiosink_name);
- is_audioactivated_ = true;
-
- } else { // fake sink
- std::string sink_name("fakesink");
- if (internal::IsTzMimeType(track->mimetype)) {
- sink_name = "tzfakesink";
- }
- CreateAudioSink_(sink_name);
- is_audioactivated_ = false;
- }
-
- GstElementLowLatency_(kTrackTypeAudio);
- pipeline_->BinAdd(Elements::kBinAudio, Elements::kAppSrcAudio,
- Elements::kDrmAudio, Elements::kDecAudio,
- Elements::kSinkAudio);
- pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinAudio);
- return true;
-}
+ auto caps = caps_builder_.Build(*track, false);
+ pipeline_->FactoryMake(Elements::kParseAudio, (GstCaps*)caps.GetCaps_(),
+ GST_ELEMENT_FACTORY_TYPE_PARSER, NULL);
-bool TrackRenderer::CreateSwAudioPipeline_(const Track* track) {
- const char* kDecoderPluginName =
- GetDecoderPluginName_(kTrackTypeAudio, track->mimetype);
- if (kDecoderPluginName == nullptr) {
+ auto parse_caps =
+ gstguard::make_guard(pipeline_->GetSrcPadCaps(Elements::kParseAudio));
+ if (!pipeline_->FactoryMake(Elements::kDecAudio, (GstCaps*)parse_caps.get(),
+ GST_ELEMENT_FACTORY_TYPE_DECODER, NULL)) {
const ErrorType err = ErrorType::kNotSupportedAudioCodec;
eventlistener_->OnError(err);
- eventlistener_->OnErrorMsg(err, const_cast<char*>(track->mimetype.c_str()));
return false;
}
- pipeline_->CreateBin(Elements::kBinAudio, "audiobin");
- std::string appsrc_mimetype = track->mimetype;
- CreateAppSrc_(kTrackTypeAudio, appsrc_mimetype);
- auto caps = caps_builder_.Build(*track, false);
- pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
+ pipeline_->FactoryMake(
+ Elements::kSinkAudio,
+ internal::GetAudioSinkPluginName(track->use_swdecoder, track->mimetype),
+ NULL);
- if (strcmp(kDecoderPluginName, kSkippedResource) != 0) {
- pipeline_->FactoryMake(Elements::kDecAudio, kDecoderPluginName, NULL);
+ pipeline_->SetProperty(Elements::kSinkAudio, "provide-clock", FALSE);
- std::string audiosink_name =
- GetAudioSinkPluginName_(track->use_swdecoder, track->mimetype);
- CreateAudioSink_(audiosink_name);
- is_audioactivated_ = true;
+ pipeline_->CreateBin(Elements::kBinAudio, "audiobin");
+ pipeline_->SignalConnect(Elements::kAppSrcAudio, "need-data",
+ G_CALLBACK(GstAudioNeedDataCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcAudio, "enough-data",
+ G_CALLBACK(GstAudioEnoughDataCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcAudio, "seek-data",
+ G_CALLBACK(GstAudioSeekDataCb_), this);
+ pipeline_->SetProperty(Elements::kAppSrcAudio, "format", GST_FORMAT_TIME);
- } else { // fake sink
- CreateAudioSink_("fakesink");
- is_audioactivated_ = false;
- }
+ pipeline_->FactoryMake(Elements::kAudioConvert, "audioconvert", nullptr);
+ pipeline_->FactoryMake(Elements::kAudioResample, "audioresample", nullptr);
- GstElementLowLatency_(kTrackTypeAudio);
pipeline_->BinAdd(Elements::kBinAudio, Elements::kAppSrcAudio,
- Elements::kDecAudio, Elements::kAudioConvert,
- Elements::kCapsFillterDefault, Elements::kAudioResample,
- Elements::kCapsFillter2, Elements::kScaleTempo,
+ Elements::kParseAudio, Elements::kDecAudio,
+ Elements::kAudioConvert, Elements::kAudioResample,
Elements::kSinkAudio);
- pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinAudio);
- return true;
-}
-bool TrackRenderer::CreateRawAudioPipeline_(const Track* track) {
- pipeline_->CreateBin(Elements::kBinAudio, "audiobin");
+ pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinAudio);
- CreateAppSrc_(kTrackTypeAudio, track->mimetype);
- auto caps = caps_builder_.Build(*track, false);
pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
- AllocatedState state = resource_manager_->GetAllocatedState(audio_out_id_);
- if (state == AllocatedState::kSuccess) {
- std::string audiosink_name =
- GetAudioSinkPluginName_(track->use_swdecoder, track->mimetype);
- CreateAudioSink_(audiosink_name);
- is_audioactivated_ = true;
+ pipeline_->SetProperty(Elements::kAppSrcAudio, "stream-type",
+ GST_APP_STREAM_TYPE_SEEKABLE);
- } else if (state == AllocatedState::kSkipped) { // fake sink
- resource_manager_->Dealloc(audio_out_id_);
+ if (volume_ != kVolumeNone) {
+ SetVolume_();
+ }
+ TRACKRENDERER_LEAVE;
+ return true;
+}
- CreateAudioSink_("fakesink");
- is_audioactivated_ = false;
+bool TrackRenderer::CreateRawAudioPipeline_(const Track* track) {
- } else { // AllocatedState::kFailed
- TRACKRENDERER_ERROR_P(this, "Fail to create raw audio pipeline!");
- return false;
- }
+ TRACKRENDERER_ENTER;
+ CreateAppSrc_(kTrackTypeAudio, track->mimetype);
+ pipeline_->FactoryMake(
+ Elements::kSinkAudio,
+ internal::GetAudioSinkPluginName(track->use_swdecoder, track->mimetype),
+ NULL);
+ pipeline_->SetProperty(Elements::kSinkAudio, "device", "hw:0,0");
+ pipeline_->SetProperty(Elements::kSinkAudio, "drift-tolerance",
+ ((200 * GST_MSECOND) / GST_USECOND));
+ pipeline_->SetProperty(Elements::kSinkAudio, "provide-clock", FALSE);
+ pipeline_->SetProperty(Elements::kSinkAudio, "sync", TRUE);
+ pipeline_->SetProperty(Elements::kSinkAudio, "force-render", FALSE);
GstElementLowLatency_(kTrackTypeAudio);
+
+ pipeline_->CreateBin(Elements::kBinAudio, "audiobin");
+ pipeline_->SignalConnect(Elements::kAppSrcAudio, "need-data",
+ G_CALLBACK(GstAudioNeedDataCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcAudio, "enough-data",
+ G_CALLBACK(GstAudioEnoughDataCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcAudio, "seek-data",
+ G_CALLBACK(GstAudioSeekDataCb_), this);
+ pipeline_->SetProperty(Elements::kAppSrcAudio, "format", GST_FORMAT_TIME);
+
+ pipeline_->FactoryMake(Elements::kAudioConvert, "audioconvert", nullptr);
+ pipeline_->FactoryMake(Elements::kCapsFillterDefault, "capsfilter", nullptr);
+ auto caps1 = gstguard::make_guard(
+ gst_caps_from_string("audio/x-raw, "
+ "format = (string) S16LE, "
+ "layout = (string) interleaved, "
+ "channels = (int) 2"));
+ pipeline_->SetProperty(Elements::kCapsFillterDefault, "caps", caps1.get());
+ pipeline_->FactoryMake(Elements::kAudioResample, "audioresample", nullptr);
+ pipeline_->FactoryMake(Elements::kCapsFillter2, "capsfilter", nullptr);
+
+ auto caps2 =
+ gstguard::make_guard(gst_caps_from_string("audio/x-raw, "
+ "rate = (int) 48000"));
+ pipeline_->SetProperty(Elements::kCapsFillter2, "caps", caps2.get());
+ pipeline_->FactoryMake(Elements::kScaleTempo, "scaletempo", nullptr);
pipeline_->BinAdd(Elements::kBinAudio, Elements::kAppSrcAudio,
Elements::kAudioConvert, Elements::kCapsFillterDefault,
Elements::kAudioResample, Elements::kCapsFillter2,
Elements::kScaleTempo, Elements::kSinkAudio);
+
pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinAudio);
+
+ auto caps = caps_builder_.Build(*track, false);
+ pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
+
+ pipeline_->SetProperty(Elements::kAppSrcAudio, "stream-type",
+ GST_APP_STREAM_TYPE_SEEKABLE);
+
+ if (volume_ != kVolumeNone) {
+ SetVolume_();
+ }
+ TRACKRENDERER_LEAVE;
return true;
}
bool TrackRenderer::CreateSubtitlePipeline_(const Track* track) {
+ TRACKRENDERER_ENTER;
pipeline_->FactoryMake(Elements::kAppSrcSubtitle, "appsrc",
"subtitle_appsrc");
- SetDefaultAppSrcSignals_(kTrackTypeSubtitle);
+ pipeline_->PadAddProbe(Elements::kAppSrcSubtitle, kPadProbeAppsrcEvent, "src",
+ (GstPadProbeType)(GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM),
+ GstPadProbeAppsrcEventCb_, this, nullptr);
pipeline_->FactoryMake(Elements::kSinkSubtitle, "fakesink", "subtitle_sink");
pipeline_->CreateBin(Elements::kBinSubtitle, "subtitlebin");
+ pipeline_->SignalConnect(Elements::kAppSrcSubtitle, "need-data",
+ G_CALLBACK(GstSubtitleNeedDataCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcSubtitle, "enough-data",
+ G_CALLBACK(GstSubtitleEnoughDataCb_), this);
+ pipeline_->SignalConnect(Elements::kAppSrcSubtitle, "seek-data",
+ G_CALLBACK(GstSubtitleSeekDataCb_), this);
pipeline_->SetProperty(Elements::kAppSrcSubtitle, "format", GST_FORMAT_TIME);
pipeline_->BinAdd(Elements::kBinSubtitle, Elements::kAppSrcSubtitle,
Elements::kSinkSubtitle);
pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinSubtitle);
- std::string mimetype = (track == nullptr) ? "" : track->mimetype;
- auto caps = gstguard::make_guard(gst_caps_new_empty_simple(mimetype.c_str()));
- pipeline_->SetProperty(Elements::kAppSrcSubtitle, "stream-type",
- GST_APP_STREAM_TYPE_SEEKABLE, "max-bytes",
- ::kMaxByteOfSubtitleSrcQueue, "caps", caps.get());
+ if (track) {
+ std::string mimetype = track->mimetype;
+ auto caps = gstguard::make_guard(gst_caps_new_empty_simple(mimetype.c_str()));
+ pipeline_->SetProperty(Elements::kAppSrcSubtitle, "stream-type",
+ GST_APP_STREAM_TYPE_SEEKABLE, "max-bytes", ::kMaxByteOfSubtitleSrcQueue,
+ "max-buffers", ::kMaxBufferOfSubtitleSrcQueue, "caps", caps.get());
+ }
pipeline_->SetProperty(Elements::kSinkSubtitle, "sync", TRUE, "async", FALSE,
"signal-handoffs", TRUE);
- GstElementLowLatency_(kTrackTypeSubtitle);
pipeline_->SignalConnect(Elements::kSinkSubtitle, "handoff",
G_CALLBACK(GstSubtitleDataHandOffCb_), this);
+ TRACKRENDERER_LEAVE;
return true;
}
bool TrackRenderer::CreatePipeline_() {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
pipeline_ = Pipeline<Elements>::Create(::kTrackRendererPipelineName);
-
- constexpr int kPrimeNumForFamilyId = 97;
- int gst_family_id =
- reinterpret_cast<std::uint32_t>(this) % kPrimeNumForFamilyId;
- TRACKRENDERER_ERROR_P(this, "gst family-id : %d", gst_family_id);
- pipeline_->SetProperty(Elements::kPipeline, "family-id", gst_family_id);
-
pipeline_->SetGstElementCreatedCbHandler(std::bind(
&TrackRenderer::GstElementCreatedCb_, this, std::placeholders::_1));
for (const auto& trackctx : trackctx_) {
if (trackctx.index != kInvalidTrackIndex) {
if (!trackctx.create_pipeline(trackctx.track)) {
- TRACKRENDERER_ERROR_P(this, "fail to create pipeline!");
+ TRACKRENDERER_ERROR("fail to create pipeline!");
// TODO(js4716.chun)
// - check if no leak.
return false;
}
}
}
+
if (trackctx_[kTrackTypeSubtitle].index == kInvalidTrackIndex) {
if (!trackctx_[kTrackTypeSubtitle].create_pipeline(nullptr)) {
- TRACKRENDERER_ERROR_P(this, "fail to create pipeline!");
+ TRACKRENDERER_ERROR("fail to create pipeline!");
return false;
}
}
pipeline_->SetSyncHandler(GstBusSyncHandlerCb_, this, nullptr);
if (!pipeline_->SetState(Elements::kPipeline, GST_STATE_READY)) {
- TRACKRENDERER_ERROR_P(this, "Set State to READY failed");
+ TRACKRENDERER_ERROR("Set State to READY failed");
return false;
}
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
-void TrackRenderer::SetDirectCrop_(const std::string& app_id) {
- if (strstr(app_id.c_str(), "UsbCamApp") ||
- strstr(app_id.c_str(), "GoogleDuoWeb")) {
- enable_direct_crop_ = true;
- }
-}
-
-void TrackRenderer::SetSequentialMode_() {
+void TrackRenderer::SetSequentialMode_(const std::string& app_id) {
bool is_supporting_seq_mode = false;
int ret = system_info_get_custom_bool(
"com.samsung/featureconf/media.support_seq_mode",
&is_supporting_seq_mode);
if (SYSTEM_INFO_ERROR_NONE != ret) {
- TRACKRENDERER_ERROR_P(
- this, "system_info_get_custom_bool() return error [%d]", ret);
+ TRACKRENDERER_ERROR("system_info_get_custom_bool() return error [%d]", ret);
return;
}
if (!is_supporting_seq_mode) {
- TRACKRENDERER_ERROR_P(this, "is_supporting_seq_mode [%d]",
- is_supporting_seq_mode);
+ TRACKRENDERER_ERROR("is_supporting_seq_mode [%d]", is_supporting_seq_mode);
return;
}
- if (!internal::IsDecoderElementNecessary(
- trackctx_[kTrackTypeVideo].track->mimetype)) {
- TRACKRENDERER_ERROR_P(this, "raw video pipeline");
- return;
+ if (strstr(app_id.c_str(), "cobalt") || strstr(app_id.c_str(), "netflix")) {
+ use_seq_mode_ = 1;
}
- constexpr std::uint32_t not_need_seq =
- kLowLatencyModeVideoDistortionConcealment | kLowLatencyModeDisableAVSync |
- kLowLatencyModeDisablePreroll | kLowLatencyModeDisableVideoQuality;
- /* sequential mode can cause other issue because these modes can't ensure
- * sync by pts */
- if (low_latency_mode_ & not_need_seq) return;
-
- use_seq_mode_ = 1;
}
void TrackRenderer::SetAppId(const std::string& app_id) {
}
void TrackRenderer::SetAppInfo(const PlayerAppInfo& app_info) {
- if (strstr(app_info.id.c_str(), "netflix")) {
- support_audio_codec_change_ = TRUE;
- support_videodec_underflow_pause_ = true;
- }
-#ifndef SOUNDBAR_PRODUCT
- else if (strcmp(app_info.id.c_str(), "org.tizen.tv-viewer") == 0) {
- avoc_sub_source_ = AVOC_SUB_SOURCE_UNIPLAYER_TVPLUS;
- }
+#ifndef DISABLE_SEQ_MODE
+ SetSequentialMode_(app_info.id);
#endif
- SetDirectCrop_(app_info.id);
- resource_manager_->SetAppId(app_info.id);
+ /* Remark : public RM does not need the app information */
playback_info_->SetAppInfo(app_info);
}
-bool TrackRenderer::GetResource_(const TrackType& type) {
+bool TrackRenderer::GetResource_() {
assert(!trackinfo_.empty());
std::list<ResourceProperty> properties;
- bool need_video_rsc =
- (type == kTrackTypeMax || type == kTrackTypeVideo) ? true : false;
- bool need_audio_rsc =
- (type == kTrackTypeMax || type == kTrackTypeAudio) ? true : false;
-
- TRACKRENDERER_INFO_P(this, "Is dual sound mode[%d]", IsDualSoundMode);
+ Track trackinfo;
for (const Track& track : trackinfo_) {
if (track.active == false) continue;
+ if (track.type != kTrackTypeVideo) continue;
+ if (internal::IsSdkEnabledFeature() || track.use_swdecoder) continue;
- if (track.type == kTrackTypeVideo && need_video_rsc) {
- bool need_renderer_resource = true;
- if (internal::IsDecoderElementNecessary(track.mimetype)) {
- ResourceProperty videodecproperty;
- videodecproperty.category = video_decoder_id_;
- videodecproperty.track = track;
- videodecproperty.is_multiview = is_multiscreen_;
- videodecproperty.rsc_alloc_policy = rsc_alloc_policy_;
-
- if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kReference) {
- videodecproperty.is_vr360 = true;
- } else if (internal::IsDisplayNeeded(display_type_) == false) {
- need_renderer_resource = false;
- }
+ ResourceProperty videodecproperty;
+ videodecproperty.category = ResourceCategory::kVideoDecoder;
+ videodecproperty.track = track;
- if (internal::IsSdkEnabledFeature()) {
- videodecproperty.use_sw = true;
- } else {
- videodecproperty.use_sw = track.use_swdecoder;
- }
- constexpr uint32_t kNdecodingMode = 0x04;
- if (video_decoding_mode_ == kNdecodingMode) {
- videodecproperty.is_ndecoding = true;
- }
- properties.push_back(videodecproperty);
- }
- if (need_renderer_resource) {
- ResourceProperty videorenderproperty;
- videorenderproperty.category = video_renderer_id_;
- videorenderproperty.is_multiview = is_multiscreen_;
- videorenderproperty.rsc_alloc_policy = rsc_alloc_policy_;
- properties.push_back(videorenderproperty);
- }
+ bool need_renderer_resource = true;
+ if (decoded_buffer_type_ ==
+ DecodedVideoFrameBufferType::kCopy) { // for videotexturing mode
+ need_renderer_resource = false;
+ } else if (decoded_buffer_type_ ==
+ DecodedVideoFrameBufferType::kReference) {
+ videodecproperty.is_vr360 = true;
}
- if (track.type == kTrackTypeAudio && need_audio_rsc) {
- bool need_renderer_resource = true;
- if (internal::IsDecoderElementNecessary(track.mimetype)) {
- ResourceProperty audiodecproperty;
- audiodecproperty.track = track;
- if (internal::IsSdkEnabledFeature()) {
- need_renderer_resource = false;
- audiodecproperty.use_sw = true;
- } else
- audiodecproperty.use_sw = track.use_swdecoder;
- audiodecproperty.category = audio_decoder_id_;
- audiodecproperty.is_dual_sound = IsDualSoundMode;
- audiodecproperty.is_multiview = is_multiscreen_;
- audiodecproperty.rsc_alloc_policy = rsc_alloc_policy_;
- properties.push_back(audiodecproperty);
- }
- if (need_renderer_resource) {
- ResourceProperty audiorenderproperty;
- audiorenderproperty.category = audio_out_id_;
- audiorenderproperty.is_dual_sound = IsDualSoundMode;
- audiorenderproperty.is_multiview = is_multiscreen_;
- audiorenderproperty.rsc_alloc_policy = rsc_alloc_policy_;
- audiorenderproperty.use_sw = track.use_swdecoder;
- properties.push_back(audiorenderproperty);
- }
+ properties.push_back(videodecproperty);
+
+ if (need_renderer_resource) {
+ ResourceProperty videorenderproperty;
+ videorenderproperty.category = ResourceCategory::kVideoRenderer;
+ properties.push_back(videorenderproperty);
}
}
- bool ret = resource_manager_->Alloc(properties);
+
+ bool ret = resource_manager_->Acquire(properties);
if (!ret) {
- TRACKRENDERER_ERROR_P(this, "GetResource_ Fail");
+ TRACKRENDERER_ERROR("GetResource_ Fail");
}
return ret;
}
}
}
-bool TrackRenderer::NeedAvocPlayerRegister_() {
- TRACKRENDERER_ENTER_P(this);
- if (internal::IsSdkEnabledFeature()) {
- TRACKRENDERER_INFO_P(this, "SDK feature, don't need avoc register");
- return false;
- }
-
- auto is_audio_track = [](const Track& item) noexcept->bool {
- return item.mimetype.find("audio") != std::string::npos;
- };
- auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
- if (target == trackinfo_.end()) {
- TRACKRENDERER_INFO_P(this, "Not found audio track");
- return false;
- }
-
- ResourceProperty audiorenderproperty;
- audiorenderproperty.category = audio_out_id_;
- audiorenderproperty.use_sw = target->use_swdecoder;
- if (resource_manager_->NeedPulseResource(audiorenderproperty)) {
- TRACKRENDERER_INFO_P(this,
- "sw decoder + pulsesink, don't need avoc register");
- return false;
- }
- TRACKRENDERER_LEAVE_P(this);
- return true;
-}
-
-bool TrackRenderer::AvocPlayerRegister_() {
- TRACKRENDERER_ENTER_P(this);
- avoc_id_ = resource_manager_->GetRawHandle();
- if (!NeedAvocPlayerRegister_()) return true;
-
- /* avoc does not care about player's audio out value, in fact avoc will check
- audio out value from RC. so we can set them with default value to
- avoc_av_player_register_m */
- need_avoc_register = true;
- int default_source_id = AVOC_AUDIO_SOURCE_MULTIMEDIA_DEC0;
- int default_audio_out = 0;
- ::PerfUsrTrace("avoc(_av)_player_register_m");
-
-#ifdef SOUNDBAR_PRODUCT
- avoc_error_e ret = avoc_av_player_register_m(
- static_cast<int>(display_->GetSurfaceId()), default_source_id,
- default_audio_out, &avoc_id_);
-#else
- avoc_error_e ret =
- avoc_player_register_m(static_cast<int>(display_->GetSurfaceId()),
- default_source_id, default_audio_out, avoc_id_);
-#endif
-
- if (ret != AVOC_EXIT_SUCCESS) {
- TRACKRENDERER_ERROR_P(this, "avoc(_av)_player_register_m failed, ret[ %d ]",
- ret);
- return false;
- }
-
- TRACKRENDERER_LEAVE_P(this);
- return true;
-}
-
-bool TrackRenderer::AvocPlayRequest_() {
- TRACKRENDERER_ENTER_P(this);
- if (resource_manager_->GetComponentName(audio_out_id_) ==
- kPulseSinkComponentName) {
- TRACKRENDERER_INFO_P(this,
- "sw decoder + pulsesink, don't need avoc request");
- return true;
- }
- auto is_audio_track = [](const Track& item) noexcept->bool {
- return item.mimetype.find("audio") != std::string::npos;
- };
- auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
- if (target == trackinfo_.end()) {
- TRACKRENDERER_INFO_P(this, "Not found audio track");
- return true;
- }
-
- if (resource_manager_->GetAllocatedState(audio_out_id_) !=
- AllocatedState::kSuccess) {
- TRACKRENDERER_INFO_P(
- this, "AllocatedState: %d",
- static_cast<int>(resource_manager_->GetAllocatedState(audio_out_id_)));
- return true;
- }
-
- int sec_ctl_source = internal::GetAvocSourceType(
- resource_manager_->IsMainDevice(audio_decoder_id_), target->use_swdecoder,
- target->mimetype);
- // AVOC uses the audio_out given by resource-center instead of player setting
- // value. if resource-center return error, AVOC use this value in 4K model.
- int audio_out =
- internal::GetAudioOut(resource_manager_->IsMainDevice(audio_out_id_));
-
- ::PerfUsrTrace("avoc(_av)_play_request_m");
-#ifdef SOUNDBAR_PRODUCT
- avoc_error_e avoc_ret =
- avoc_av_play_request_m(avoc_id_, sec_ctl_source, audio_out);
-#else
- avoc_error_e avoc_ret =
- avoc_play_request_m(avoc_id_, sec_ctl_source, audio_out);
-#endif
-
- if (avoc_ret != AVOC_EXIT_SUCCESS) {
- TRACKRENDERER_ERROR_P(this, "avoc(_av)_play_request_m failed, ret[ %d ]",
- avoc_ret);
- return false;
- }
-
- TRACKRENDERER_LEAVE_P(this);
- return true;
-}
-
-bool TrackRenderer::AvocPlayerUnRegister_() {
- TRACKRENDERER_ENTER_P(this);
- if (avoc_id_ < 0) {
- TRACKRENDERER_INFO_P(this, "Avoc has been deinitialized");
- return true;
- }
- if (!need_avoc_register) return true;
- avoc_error_e ret = AVOC_EXIT_SUCCESS;
-#ifdef SOUNDBAR_PRODUCT
- ret = avoc_av_player_unregister(avoc_id_);
-#else
- ret = avoc_player_unregister(avoc_id_);
-#endif
- if (ret != AVOC_EXIT_SUCCESS) {
- TRACKRENDERER_ERROR_P(this, "avoc(_av)_player_unregister() is failed");
- return false;
- }
-
- avoc_id_ = -1;
- need_avoc_register = false;
- TRACKRENDERER_LEAVE_P(this);
- return true;
-}
-
-bool TrackRenderer::AddAiFilter_(void* aifilter) {
- TRACKRENDERER_ENTER_P(this);
- if (aifilter == nullptr) return false;
- RemoveAiFilter_();
- aifilter_ = gst_object_ref(aifilter);
- return true;
-}
-
-void TrackRenderer::RemoveAiFilter_() {
- TRACKRENDERER_ENTER_P(this);
- if (aifilter_ == nullptr) return;
- gst_object_unref(aifilter_);
- aifilter_ = nullptr;
- return;
-}
-
bool TrackRenderer::ReleaseResource_() {
- TRACKRENDERER_ENTER_P(this);
- latency_manager_->UnsetPipeline();
+ TRACKRENDERER_ENTER;
pipeline_.reset();
- AvocPlayerUnRegister_();
- RemoveAiFilter_();
-
- if (!resource_manager_->Dealloc()) {
- TRACKRENDERER_ERROR_P(this, "resource manager dealloc fail!");
+ if (!resource_manager_->Release()) {
+ TRACKRENDERER_ERROR("resource manager Release fail!");
}
for (int i = 0; i < kTrackTypeMax; ++i) {
trackctx_[i].need_update_segment = true;
}
trackinfo_.clear();
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
-// LCOV_EXCL_START
void TrackRenderer::OnResourceConflicted() {
- TRACKRENDERER_ENTER_E_P(this);
+ TRACKRENDERER_ENTER_E;
resource_cv_.notify_one();
state_ = State::kResourceConflicted;
eventlistener_->OnResourceConflicted();
-}
-
-void TrackRenderer::OnVideoLatencyStatus(const LatencyStatus& latency_status) {
- TRACKRENDERER_ENTER_E_P(this);
- eventlistener_->OnVideoLatencyStatus(latency_status);
-}
-
-void TrackRenderer::OnAudioLatencyStatus(const LatencyStatus& latency_status) {
- TRACKRENDERER_ENTER_E_P(this);
- eventlistener_->OnAudioLatencyStatus(latency_status);
-}
-
-void TrackRenderer::OnVideoHighLatency() {
- TRACKRENDERER_ENTER_E_P(this);
- eventlistener_->OnVideoHighLatency();
-}
-
-void TrackRenderer::OnAudioHighLatency() {
- TRACKRENDERER_ENTER_E_P(this);
- eventlistener_->OnAudioHighLatency();
-}
-
-SubtitleType TrackRenderer::GetSubtitleType_(const GstBuffer* buf) {
- auto is_subtitle_track = [](const Track& track) noexcept->bool {
- return ((track.type == kTrackTypeSubtitle) && (track.active));
- };
-
- auto subtitle_track =
- std::find_if(trackinfo_.begin(), trackinfo_.end(), is_subtitle_track);
- if (subtitle_track == trackinfo_.end()) {
- TRACKRENDERER_ERROR_P(this, "Not found subtitle track info");
- return SubtitleType::kInvalid;
- }
-
- TRACKRENDERER_DEBUG_P(this, "subtitle_track->mimetype = [%s]",
- (subtitle_track->mimetype).c_str());
-
- if ((subtitle_track->mimetype).find("x-xsub") != std::string::npos ||
- (subtitle_track->mimetype).find("x-smpte-png") != std::string::npos ||
- (subtitle_track->mimetype).find("video/x-raw") != std::string::npos) {
- TRACKRENDERER_DEBUG_P(this, "It is Picture type subtitle");
- return SubtitleType::kPicture;
- }
-
- if (((subtitle_track->mimetype).find("x-smpte-text") != std::string::npos) ||
- ((subtitle_track->mimetype).find("stpp") != std::string::npos)) {
- TRACKRENDERER_DEBUG_P(this, "Find the x-smpte-text");
- gint* picture_flag = (gint*)gst_mini_object_get_qdata(
- GST_MINI_OBJECT(buf), g_quark_from_static_string("picture_flag"));
- TRACKRENDERER_DEBUG_P(this, "picture_flag = [%p]", picture_flag);
- if (picture_flag && (1 == *picture_flag)) {
- TRACKRENDERER_DEBUG_P(this,
- "It is Picture type subtitle for x-smpte-text");
- return SubtitleType::kPicture;
- }
- }
-
- TRACKRENDERER_DEBUG_P(this, "It is TEXT type subtitle");
- return SubtitleType::kText;
+ TRACKRENDERER_LEAVE_E;
}
void TrackRenderer::GstSubtitleDataHandOffCb_(GstElement* object,
GstBuffer* buf, GstPad* pad,
gpointer userdata) {
- auto trackrenderer = static_cast<TrackRenderer*>(userdata);
- if (trackrenderer == nullptr) {
- TRACKRENDERER_ERROR_P(trackrenderer, "trackrenderer == nullptr");
- return;
- }
TRACKRENDERER_DEBUG("Subtitle Buffer :Timestamp:[%" GST_TIME_FORMAT "]",
GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)));
- const SubtitleType type = trackrenderer->GetSubtitleType_(buf);
- if (type == SubtitleType::kInvalid) return;
- auto inbuffer = DecoderInputBuffer::Create(kTrackTypeSubtitle, 0, buf);
- trackrenderer->eventlistener_->OnSubtitleData(std::move(inbuffer), type);
-#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
- SubtitleAttrParser sub_attr_parser(buf);
- auto attr_list = sub_attr_parser.Parse();
- if (!attr_list && gst_buffer_get_size(buf) > 0) {
- TRACKRENDERER_ERROR_P(trackrenderer, "attr_list is NULL");
+ auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+ if (trackrenderer == nullptr) {
+ TRACKRENDERER_ERROR("trackrenderer is nullptr");
return;
}
- GstMapInfo info;
- gst_buffer_map(buf, &info, GST_MAP_READ);
- char* buffer = reinterpret_cast<char*>(info.data);
- GstClockTime duration = GST_CLOCK_TIME_NONE;
- duration = GST_TIME_AS_MSECONDS(GST_BUFFER_DURATION(buf));
- trackrenderer->eventlistener_->OnSubtitleData(buffer, info.size, type,
- duration, std::move(attr_list));
- gst_buffer_unmap(buf, &info);
-#endif
+ auto inbuffer = DecoderInputBuffer::Create(kTrackTypeSubtitle, 0, buf);
+ trackrenderer->eventlistener_->OnSubtitleData(std::move(inbuffer), SubtitleType::kText);
}
void TrackRenderer::GstClosedCaptionHandOffCb_(GstElement* object,
auto trackrenderer = static_cast<TrackRenderer*>(userdata);
GstMapInfo info;
gst_buffer_map(buf, &info, GST_MAP_READ);
- // TRACKRENDERER_DEBUG_P(trackrenderer, "data[%p], size[%d]", info.data,
- // info.size);
+ TRACKRENDERER_DEBUG("data[%p], size[%" G_GSIZE_FORMAT"]", info.data, info.size);
char* buffer = reinterpret_cast<char*>(info.data);
trackrenderer->eventlistener_->OnClosedCaptionData(buffer, info.size);
void TrackRenderer::GstClosedCaptionPadAddedCb_(GstElement* element,
GstPad* pad,
gpointer userdata) {
- auto trackrenderer = static_cast<TrackRenderer*>(userdata);
- TRACKRENDERER_ENTER_P(trackrenderer);
+ TRACKRENDERER_ENTER;
if (!element || !pad) {
assert(element);
assert(pad);
- TRACKRENDERER_ERROR_P(trackrenderer, "NULL object element[%p] pad[%p]",
- element, pad);
+ TRACKRENDERER_ERROR("NULL object element[%p] pad[%p]", element, pad);
return;
}
auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad));
if (!caps.get()) {
- TRACKRENDERER_ERROR_P(trackrenderer, "caps is NULL");
+ TRACKRENDERER_ERROR("caps is NULL");
return;
}
GstStructure* gststr = gst_caps_get_structure(caps.get(), 0);
if (!gststr) {
assert(gststr);
- TRACKRENDERER_ERROR_P(trackrenderer, "GstStructure is NULL");
+ TRACKRENDERER_ERROR("GstStructure is NULL");
return;
}
std::string name = gst_structure_get_name(gststr);
- if (name != "text/dtv-closed-caption") {
- TRACKRENDERER_ERROR_P(trackrenderer, "NOT closed caption");
+ if (name != "closedcaption/x-cea-708" && name != "closedcaption/x-cea-608") {
+ TRACKRENDERER_ERROR("NOT closed caption: %s", name.c_str());
return;
}
+ auto trackrenderer = static_cast<TrackRenderer*>(userdata);
assert(trackrenderer);
assert(trackrenderer->pipeline_.get());
if (!trackrenderer->pipeline_->FactoryMake(Elements::kQueueCaption, "queue",
assert(0);
return;
}
-
- /*Not limit the time and buffer size of caption queue*/
- trackrenderer->pipeline_->SetProperty(Elements::kQueueCaption,
- "max-size-time", (guint64)0,
- "max-size-buffers", (guint)0);
+ if (!trackrenderer->pipeline_->FactoryMake(Elements::kCCConverter, "ccconverter",
+ nullptr)) {
+ assert(0);
+ return;
+ }
+ if (!trackrenderer->pipeline_->FactoryMake(Elements::kCCCapsFilter, "capsfilter",
+ nullptr)) {
+ assert(0);
+ return;
+ }
+ auto cc_caps = gstguard::make_guard(gst_caps_from_string("closedcaption/x-cea-708, "
+ "format = (string) cdp"));
+ trackrenderer->pipeline_->SetProperty(Elements::kCCCapsFilter, "caps", cc_caps.get());
if (!trackrenderer->pipeline_->FactoryMake(Elements::kSinkCaption, "fakesink",
"caption_sink")) {
return;
}
trackrenderer->pipeline_->SetProperty(Elements::kSinkCaption, "sync", TRUE,
- "async", FALSE, "signal-handoffs", TRUE,
- "is-subtitle", TRUE);
- trackrenderer->GstElementLowLatency_(kTrackTypeSubtitle);
+ "async", FALSE, "signal-handoffs",
+ TRUE);
trackrenderer->pipeline_->SignalConnect(
Elements::kSinkCaption, "handoff", G_CALLBACK(GstClosedCaptionHandOffCb_),
userdata);
trackrenderer->pipeline_->BinAddSimple(Elements::kBinVideo,
Elements::kQueueCaption);
- trackrenderer->pipeline_->ElementLink(Elements::kDecVideo,
+ trackrenderer->pipeline_->ElementLink(Elements::kCCExtractor,
Elements::kQueueCaption);
- trackrenderer->pipeline_->BinAdd(Elements::kBinVideo, Elements::kSinkCaption);
- TRACKRENDERER_LEAVE_P(trackrenderer);
+ trackrenderer->pipeline_->BinAdd(Elements::kBinVideo,
+ Elements::kCCConverter,
+ Elements::kCCCapsFilter,
+ Elements::kSinkCaption);
+ TRACKRENDERER_LEAVE;
}
-// LCOV_EXCL_STOP
void TrackRenderer::CompleteSeeking_() {
if (!is_async_done_ || !is_seeking_) return;
- TRACKRENDERER_ERROR_P(this, "Seeking has been completed SubState[%d]",
- static_cast<int>(target_substate_));
+ TRACKRENDERER_ERROR("Seeking has been completed SubState[%d]",
+ static_cast<int>(target_substate_));
eventlistener_->OnSeekDone();
is_seeking_ = false;
is_async_done_ = false;
switch (GST_MESSAGE_TYPE(message)) {
case GST_MESSAGE_UNKNOWN:
- TRACKRENDERER_ERROR_P(trackrenderer, "GST_MESSAGE_UNKNOWN");
+ TRACKRENDERER_ERROR("GST_MESSAGE_UNKNOWN");
break;
case GST_MESSAGE_EOS: {
- TRACKRENDERER_ERROR_P(trackrenderer, "GST_MESSAGE_EOS");
+ TRACKRENDERER_ERROR("GST_MESSAGE_EOS");
trackrenderer->eventlistener_->OnEos();
break;
}
gst_message_parse_state_changed(message, &old_state, &new_state,
&pending_state);
std::string message_src_name(GST_MESSAGE_SRC_NAME(message));
- gst_util::ShowStateChangedMsg(message, trackrenderer);
if (message_src_name == ::kTrackRendererPipelineName) {
+ TRACKRENDERER_DEBUG("GST_MESSAGE_STATE_CHANGED o:%d, n:%d, %s", old_state, new_state, message_src_name.c_str());
+ gst_util::ShowStateChangedMsg(message);
+
if (old_state == GST_STATE_NULL && new_state == GST_STATE_READY &&
pending_state == GST_STATE_VOID_PENDING) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "PIPELINE STATE CHANGED FROM NULL to READY");
+ TRACKRENDERER_ERROR("PIPELINE STATE CHANGED FROM NULL to READY");
} else if (old_state == GST_STATE_READY &&
new_state == GST_STATE_PAUSED) {
trackrenderer->state_ = State::kWorking;
+ TRACKRENDERER_DEBUG("resource_cv.notifi_one");
trackrenderer->resource_cv_.notify_one();
+ TRACKRENDERER_DEBUG("resource_cv.notifi_one DONE");
trackrenderer->UpdatePlaybackInfo_(false);
- TRACKRENDERER_ERROR_P(trackrenderer,
- "PIPELINE STATE CHANGED FROM READY to PAUSED");
+ TRACKRENDERER_ERROR("PIPELINE STATE CHANGED FROM READY to PAUSED");
} else if (old_state == GST_STATE_PAUSED &&
- new_state == GST_STATE_PLAYING &&
- pending_state == GST_STATE_VOID_PENDING) {
- trackrenderer->screen_saver_->StartTimeout();
- TRACKRENDERER_ERROR_P(
- trackrenderer, "PIPELINE STATE CHANGED FROM PAUSED to PLAYING");
+ new_state == GST_STATE_PLAYING &&
+ pending_state == GST_STATE_VOID_PENDING) {
+ TRACKRENDERER_ERROR("PIPELINE STATE CHANGED FROM PAUSED to PLAYING");
trackrenderer->CompleteSeeking_();
} else if (old_state == GST_STATE_PLAYING &&
- new_state == GST_STATE_PAUSED) {
- trackrenderer->screen_saver_->StopTimeout();
+ new_state == GST_STATE_PAUSED) {
} else if (new_state == GST_STATE_NULL &&
- pending_state == GST_STATE_VOID_PENDING) {
- trackrenderer->screen_saver_->StopTimeout();
+ pending_state == GST_STATE_VOID_PENDING) {
}
}
break;
} // case GST_MESSAGE_STATE_CHANGED
case GST_MESSAGE_ELEMENT: {
- TRACKRENDERER_INFO_P(trackrenderer, "GST_MESSAGE_ELEMENT");
+ TRACKRENDERER_INFO("GST_MESSAGE_ELEMENT");
const gchar* struct_name =
gst_structure_get_name(gst_message_get_structure(message));
if (!strcmp(struct_name, "resolution_is_changed")) {
int is_changed = 0;
gst_structure_get_int(gst_message_get_structure(message),
"Resolution_changed", &is_changed);
- TRACKRENDERER_ERROR_P(trackrenderer, "resolution is changed - [%d]",
- is_changed);
+ TRACKRENDERER_ERROR("resolution is changed - [%d]", is_changed);
if (1 == is_changed) {
trackrenderer->UpdatePlaybackInfo_(true);
EventMsg event_msg;
trackrenderer->eventlistener_->OnEvent(EventType::kResolutionChanged,
event_msg);
}
- } else if (!strcmp(struct_name, "omx_vdec_underflow")) {
- GstState element_state = GST_STATE_VOID_PENDING;
- trackrenderer->pipeline_->GetState(Elements::kPipeline, &element_state,
- NULL, 10 * GST_MSECOND);
- TRACKRENDERER_WARN_P(
- trackrenderer,
- "omx_vdec_underflow will be posted, current state[%s]",
- gst_element_state_get_name(element_state));
- if (element_state == GST_STATE_PLAYING) {
- trackrenderer->eventlistener_->OnVideoDecoderUnderrun();
- }
}
break;
} // case GST_MESSAGE_ELEMENT
case GST_MESSAGE_ASYNC_DONE: {
- TRACKRENDERER_ERROR_P(trackrenderer, "GST_MESSAGE_ASYNC_DONE");
+ TRACKRENDERER_ERROR("GST_MESSAGE_ASYNC_DONE");
trackrenderer->is_async_done_ = true;
if (trackrenderer->target_substate_ != SubState::kPlaying) {
trackrenderer->CompleteSeeking_();
if (trackrenderer->is_flushing_) {
trackrenderer->eventlistener_->OnFlushDone();
trackrenderer->is_flushing_ = false;
- trackrenderer->enable_audio_track_change_ = false;
}
break;
}
- // LCOV_EXCL_START
case GST_MESSAGE_ERROR: {
- TRACKRENDERER_ERROR_P(trackrenderer, "GST_MESSAGE_ERROR");
+ TRACKRENDERER_ERROR("GST_MESSAGE_ERROR");
trackrenderer->resource_cv_.notify_one();
bool is_music_content =
trackrenderer->trackctx_[kTrackTypeVideo].index != kInvalidTrackIndex
? false
: true;
const ErrorType err = HandleError(message, is_music_content);
- if (trackrenderer->is_error_posted_) {
- TRACKRENDERER_INFO_P(trackrenderer, "error is already posted");
- break;
- }
trackrenderer->eventlistener_->OnError(err);
- gchar* error_msg = nullptr;
- HandleErrorMsg(message, &error_msg);
- auto debug = gstguard::make_guard(error_msg);
- if (debug != nullptr) {
- trackrenderer->eventlistener_->OnErrorMsg(err, debug.get());
- }
- trackrenderer->is_error_posted_ = true;
break;
} // case GST_MESSAGE_ERROR
- // LCOV_EXCL_STOP
default: {
- TRACKRENDERER_INFO_P(
- trackrenderer, "thread[ %p ], msg[ %p / %s ] src[ %s ]",
- g_thread_self(), message, GST_MESSAGE_TYPE_NAME(message),
- GST_MESSAGE_SRC_NAME(message));
+#ifdef __DEBUG__
+ TRACKRENDERER_INFO(
+ "thread[ %p ], msg[ %p / %s ] src[ %s ]", g_thread_self(), message,
+ GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC_NAME(message));
+#endif
+ break;
}
}
gst_message_unref(message);
gpointer userdata) {
auto trackrenderer = static_cast<TrackRenderer*>(userdata);
trackrenderer->trackctx_[kTrackTypeVideo].is_enough_data = false;
+
trackrenderer->eventlistener_->OnBufferStatus(kTrackTypeVideo,
- BufferStatus::kUnderrun);
+ BufferStatus::kUnderrun);
}
void TrackRenderer::GstSubtitleNeedDataCb_(GstElement* element, guint size,
void TrackRenderer::GstVideoEnoughDataCb_(GstElement* element,
gpointer userdata) {
+ TRACKRENDERER_ENTER;
auto trackrenderer = static_cast<TrackRenderer*>(userdata);
trackrenderer->trackctx_[kTrackTypeVideo].is_enough_data = true;
trackrenderer->eventlistener_->OnBufferStatus(kTrackTypeVideo,
BufferStatus::kOverrun);
+ TRACKRENDERER_LEAVE;
}
void TrackRenderer::GstSubtitleEnoughDataCb_(GstElement* element,
gboolean TrackRenderer::GstAudioSeekDataCb_(GstElement* element, guint64 offset,
gpointer user_data) {
+ TRACKRENDERER_ENTER;
+ TRACKRENDERER_INFO("offset : %" PRIu64 "", offset);
auto trackrenderer = static_cast<TrackRenderer*>(user_data);
- TRACKRENDERER_INFO_P(trackrenderer, "offset : %llu", offset);
trackrenderer->eventlistener_->OnSeekData(kTrackTypeAudio,
offset / GST_MSECOND);
+ TRACKRENDERER_LEAVE;
return true;
}
gboolean TrackRenderer::GstVideoSeekDataCb_(GstElement* element, guint64 offset,
gpointer user_data) {
+ TRACKRENDERER_ENTER;
+ TRACKRENDERER_INFO("offset : %" PRIu64 "", offset);
auto trackrenderer = static_cast<TrackRenderer*>(user_data);
- TRACKRENDERER_INFO_P(trackrenderer, "offset : %llu", offset);
trackrenderer->eventlistener_->OnSeekData(kTrackTypeVideo,
offset / GST_MSECOND);
+ TRACKRENDERER_LEAVE;
return true;
}
gboolean TrackRenderer::GstSubtitleSeekDataCb_(GstElement* element,
guint64 offset,
gpointer user_data) {
- auto trackrenderer = static_cast<TrackRenderer*>(user_data);
- TRACKRENDERER_INFO_P(trackrenderer, "offset : %llu", offset);
+ TRACKRENDERER_ENTER;
+ TRACKRENDERER_INFO("offset : %" PRIu64 "", offset);
return true;
}
-// LCOV_EXCL_START
gboolean TrackRenderer::GstAudioDrmInitDataCb_(int* drmhandle, unsigned int len,
unsigned char* psshdata,
void* userdata) {
+ TRACKRENDERER_ENTER;
auto trackrenderer = static_cast<TrackRenderer*>(userdata);
- TRACKRENDERER_ENTER_P(trackrenderer);
trackrenderer->eventlistener_->OnDrmInitData(drmhandle, len, psshdata,
kTrackTypeAudio);
- TRACKRENDERER_LEAVE_P(trackrenderer);
+ TRACKRENDERER_LEAVE;
return TRUE;
}
gboolean TrackRenderer::GstVideoDrmInitDataCb_(int* drmhandle, unsigned int len,
unsigned char* psshdata,
void* userdata) {
+ TRACKRENDERER_ENTER;
auto trackrenderer = static_cast<TrackRenderer*>(userdata);
- TRACKRENDERER_ENTER_P(trackrenderer);
trackrenderer->eventlistener_->OnDrmInitData(drmhandle, len, psshdata,
kTrackTypeVideo);
- TRACKRENDERER_LEAVE_P(trackrenderer);
+ TRACKRENDERER_LEAVE;
return TRUE;
}
-// LCOV_EXCL_STOP
void TrackRenderer::GstElementCreatedCb_(Elements element) {
auto it = kAttributesByElem_.find(element);
void* userdata) {
GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
GST_MINI_OBJECT(buffer), g_quark_from_static_string("v4l2_info")));
- auto trackrenderer = static_cast<TrackRenderer*>(userdata);
if (!s) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "scaler buffer don't have v4l2_info structure");
+ TRACKRENDERER_ERROR("scaler buffer don't have v4l2_info structure");
return;
}
int width, height, y_linesize, c_linesize, y_fd, c_fd, plane_num;
gst_structure_get_int(s, "u_phyaddr", &c_fd);
gst_structure_get_int(s, "plane_num", &plane_num);
+ auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+
tbm_bo bo_Y =
tbm_bo_import_fd(trackrenderer->tbm_buffer_manager_->bufmgr, y_fd);
if (bo_Y == nullptr) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "[Weak Ref] tbm_bo_import_fd() error : Y bo is NULL");
+ TRACKRENDERER_ERROR("[Weak Ref] tbm_bo_import_fd() error : Y bo is NULL");
return;
}
BOOST_SCOPE_EXIT(&bo_Y) {
tbm_bo bo_C =
tbm_bo_import_fd(trackrenderer->tbm_buffer_manager_->bufmgr, c_fd);
if (bo_C == nullptr) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "[Weak Ref] tbm_bo_import_fd() error : C bo is NULL");
+ TRACKRENDERER_ERROR("[Weak Ref] tbm_bo_import_fd() error : C bo is NULL");
return;
}
BOOST_SCOPE_EXIT(&bo_C) {
tbm_surface_h tbm_surf =
tbm_surface_internal_create_with_bos(&info, bo, info.num_planes);
if (!tbm_surf) {
- TRACKRENDERER_ERROR_P(trackrenderer, "failed to create tbm surface");
+ TRACKRENDERER_ERROR("failed to create tbm surface");
return;
}
GstBuffer* buffer, GstPad* pad,
void* userdata) {
auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad));
- auto trackrenderer = static_cast<TrackRenderer*>(userdata);
if (!caps.get()) {
- TRACKRENDERER_ERROR_P(trackrenderer, "caps is NULL");
+ TRACKRENDERER_ERROR("caps is NULL");
return;
}
GstVideoInfo info;
if (!gst_video_info_from_caps(&info, caps.get())) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "fail to get gst_video_info_from_caps()");
+ TRACKRENDERER_ERROR("fail to get gst_video_info_from_caps()");
return;
}
- VideoColorFormat colorformat = VideoColorFormat::kColorFormatNV12;
- GstStructure* structure = gst_caps_get_structure(caps.get(), 0);
- const gchar* color_format =
- gst_structure_get_string(structure, "color-format");
- if (color_format && strstr(color_format, "NV16"))
- colorformat = VideoColorFormat::kColorFormatNV16;
- tbm_surface_h tbm_surf_t = nullptr;
- internal::VideoStreamDataType stream = {};
+ internal::VideoStreamDataType stream;
+ //memset(&stream, 0x0, sizeof(stream));
+ stream.format = TBM_FORMAT_NV12;
+ stream.width = info.width;
+ stream.height = info.height;
+ stream.elevation[GST_VIDEO_COMP_Y] = info.height;
+ stream.elevation[GST_VIDEO_COMP_U] = info.height / 2;
+
+ auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+
+ tbm_surface_h tbm_surf_t =
+ tbm_surface_create(stream.width, stream.height, TBM_FORMAT_NV12);
BOOST_SCOPE_EXIT(&tbm_surf_t) {
if (tbm_surf_t) {
}
BOOST_SCOPE_EXIT_END
+ stream.bo[GST_VIDEO_COMP_Y] =
+ tbm_surface_internal_get_bo(tbm_surf_t, GST_VIDEO_COMP_Y);
+ if (!stream.bo[GST_VIDEO_COMP_Y]) {
+ TRACKRENDERER_ERROR("[bo Y] tbm_surface_internal_get_bo failed");
+ return;
+ }
+
+ stream.bo[GST_VIDEO_COMP_U] =
+ tbm_surface_internal_get_bo(tbm_surf_t, GST_VIDEO_COMP_U);
+ if (!stream.bo[GST_VIDEO_COMP_U]) {
+ TRACKRENDERER_ERROR("[bo C] tbm_surface_internal_get_bo failed");
+ return;
+ }
+
+ tbm_surface_internal_get_plane_data(
+ tbm_surf_t, GST_VIDEO_COMP_Y, NULL, NULL,
+ (uint32_t*)&stream.stride[GST_VIDEO_COMP_Y]);
+ tbm_surface_internal_get_plane_data(
+ tbm_surf_t, GST_VIDEO_COMP_U, NULL, NULL,
+ (uint32_t*)&stream.stride[GST_VIDEO_COMP_U]);
+
if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_STV0) {
GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
GST_MINI_OBJECT(buffer), g_quark_from_static_string("v4l2_info")));
if (!s) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "scaler buffer don't have v4l2_info structure");
+ TRACKRENDERER_ERROR("scaler buffer don't have v4l2_info structure");
return;
}
- int y_linesize, c_linesize, y_viraddr, c_viraddr, plane_num = 0;
- int width = 0, height = 0;
- gst_structure_get_int(s, "width", &width);
- gst_structure_get_int(s, "height", &height);
- gst_structure_get_int(s, "y_viraddr", &y_viraddr);
- gst_structure_get_int(s, "u_viraddr", &c_viraddr);
+
+ int y_linesize, c_linesize, plane_num = 0;
+ unsigned int y_viraddr_i, c_viraddr_i = 0;
+ uintptr_t y_viraddr, c_viraddr;
gst_structure_get_int(s, "y_linesize", &y_linesize);
gst_structure_get_int(s, "u_linesize", &c_linesize);
gst_structure_get_int(s, "plane_num", &plane_num);
+ gst_structure_get_uint(s, "y_viraddr", &y_viraddr_i);
+ gst_structure_get_uint(s, "u_viraddr", &c_viraddr_i);
- if (internal::FillVideoStreamDataAndTbmSurface(&stream, &tbm_surf_t, width,
- height) == false) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "FillVideoStreamDataAndTbmSurface fail");
- return;
- }
-
+ y_viraddr = (uintptr_t)y_viraddr_i;
+ c_viraddr = (uintptr_t)c_viraddr_i;
if (!internal::CopyHwCodec(stream, y_viraddr, c_viraddr, y_linesize,
- c_linesize, colorformat)) {
- TRACKRENDERER_ERROR_P(trackrenderer, "data copy fail");
+ c_linesize)) {
+ TRACKRENDERER_ERROR("data copy fail");
return;
}
} else if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_STV1) {
- if (internal::FillVideoStreamDataAndTbmSurface(
- &stream, &tbm_surf_t, info.width, info.height) == false) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "FillVideoStreamDataAndTbmSurface fail");
- return;
- }
-
if (!internal::CopySwCodec(buffer, stream)) {
- TRACKRENDERER_ERROR_P(trackrenderer, "data copy fail");
+ TRACKRENDERER_ERROR("data copy fail");
return;
}
}
+
tbm_surface_h tbm_surf = internal::CreateTbmSurfaceWithBos(stream);
DecodedVideoPacket packet;
return;
}
-// LCOV_EXCL_START
-void TrackRenderer::GstDecodedVideoRawBufferCb_(GstElement* element,
- GstBuffer* buffer, GstPad* pad,
- void* userdata) {
- auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad));
- auto trackrenderer = static_cast<TrackRenderer*>(userdata);
- if (!caps.get()) {
- TRACKRENDERER_ERROR_P(trackrenderer, "caps is NULL");
- return;
- }
- GstVideoInfo info;
- if (!gst_video_info_from_caps(&info, caps.get())) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "fail to get gst_video_info_from_caps()");
- return;
- }
-
- DecodedVideoRawModePacket packet;
-
- int width = 0, height = 0;
- if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_STV0) {
- GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
- GST_MINI_OBJECT(buffer), g_quark_from_static_string("v4l2_info")));
- if (!s) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "scaler buffer doesn't have v4l2_info structure");
- return;
- }
- packet.type = DecodedVideoRawModePacketType::kPhysicalAddress;
- gst_structure_get_int(s, "width", &width);
- gst_structure_get_int(s, "height", &height);
- gst_structure_get_int(s, "y_phyaddr", &packet.data.raw.y_phyaddr);
- gst_structure_get_int(s, "u_phyaddr", &packet.data.raw.uv_phyaddr);
- gst_structure_get_int(s, "y_viraddr", &packet.data.raw.y_viraddr);
- gst_structure_get_int(s, "u_viraddr", &packet.data.raw.uv_viraddr);
- gst_structure_get_int(s, "y_linesize", &packet.data.raw.y_linesize);
- gst_structure_get_int(s, "u_linesize", &packet.data.raw.uv_linesize);
- } else if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_STV1) {
- GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
- GST_MINI_OBJECT(buffer), g_quark_from_static_string("tbm_bo")));
- width = info.width;
- height = info.height;
- if (s) {
- packet.type = DecodedVideoRawModePacketType::kTizenBuffer;
- if (!gst_structure_get(s, "tbm_bo_key", G_TYPE_UINT, &packet.data.tbm.key,
- NULL)) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "Buffer doesn't have tbm_bo_hnd structure");
- return;
- }
- } else {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "Buffer doesn't have tbm_bo structure");
- return;
- }
- }
-
- packet.width = width;
- packet.height = height;
- packet.pts = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer)); // ns -> ms
-
- trackrenderer->eventlistener_->OnMediaRawPacketVideoDecoded(packet);
- return;
-}
-
-void TrackRenderer::GstDecodedVideoScaleBufferCb_(GstElement* element,
- GstBuffer* buffer,
- GstPad* pad, void* userdata) {
- auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad));
- auto trackrenderer = static_cast<TrackRenderer*>(userdata);
- if (!caps.get()) {
- TRACKRENDERER_ERROR_P(trackrenderer, "caps is NULL");
- return;
- }
- GstVideoInfo info;
- if (!gst_video_info_from_caps(&info, caps.get())) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "fail to get gst_video_info_from_caps()");
- return;
- }
- if (trackrenderer->NeedDropThisDecodedVideoBuffer_()) {
- return;
- }
- std::lock_guard<std::mutex> lk(trackrenderer->scale_target_m_);
- internal::VideoStreamDataType stream = {};
- stream.format = TBM_FORMAT_NV12;
- stream.width = trackrenderer->scale_target_width_;
- stream.height = trackrenderer->scale_target_height_;
- stream.elevation[GST_VIDEO_COMP_Y] = trackrenderer->scale_target_height_;
- stream.elevation[GST_VIDEO_COMP_U] = trackrenderer->scale_target_height_ / 2;
- VideoColorFormat colorformat = VideoColorFormat::kColorFormatNV12;
- GstStructure* structure = gst_caps_get_structure(caps.get(), 0);
- const gchar* color_format =
- gst_structure_get_string(structure, "color-format");
- if (color_format && strstr(color_format, "NV16"))
- colorformat = VideoColorFormat::kColorFormatNV16;
- // using cb to get the free tbm ptr, if not find then new one, else, using it
- tbm_surface_h tbm_surf_t = nullptr;
- void* tbm_surf = nullptr;
- bool exception_flag = true;
- DecodedVideoPacket packet;
-
- BOOST_SCOPE_EXIT(&tbm_surf_t, &tbm_surf, &exception_flag) {
- if (!tbm_surf && tbm_surf_t && exception_flag == true) {
- tbm_surface_destroy(tbm_surf_t);
- tbm_surf_t = nullptr;
- }
- }
- BOOST_SCOPE_EXIT_END
-
- if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_STV0) {
- GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
- GST_MINI_OBJECT(buffer), g_quark_from_static_string("v4l2_info")));
- if (!s) {
- TRACKRENDERER_ERROR_P(trackrenderer,
- "scaler buffer don't have v4l2_info structure");
- return;
- }
- int y_linesize, c_linesize, y_phyaddr, u_phyaddr, plane_num = 0;
- int width = 0, height = 0;
- CropArea crop_info;
- int x, y, w, h = 0;
- gst_structure_get_int(s, "width", &width);
- gst_structure_get_int(s, "height", &height);
- gst_structure_get_int(s, "y_phyaddr", &y_phyaddr);
- gst_structure_get_int(s, "u_phyaddr", &u_phyaddr);
- gst_structure_get_int(s, "y_linesize", &y_linesize);
- gst_structure_get_int(s, "u_linesize", &c_linesize);
- gst_structure_get_int(s, "plane_num", &plane_num);
- if (!y_phyaddr || !u_phyaddr) {
- TRACKRENDERER_ERROR_P(trackrenderer, "invalid y_phyaddr or u_phyaddr");
- return;
- }
- if (!width || !height) {
- TRACKRENDERER_WARN_P(
- trackrenderer,
- "invalid width or height, using width&&height of caps_info");
- width = info.width;
- height = info.height;
- }
-
- tbm_surface_info_s surface_info;
- trackrenderer->eventlistener_->OnMediaPacketGetTbmBufPtr(
- &tbm_surf, trackrenderer->is_scale_size_changed_);
- trackrenderer->is_scale_size_changed_ = false;
- if (tbm_surf == nullptr) {
- tbm_surf_t = tbm_surface_internal_create_with_flags(
- stream.width, stream.height, TBM_FORMAT_NV12,
- (1 << 17 | TBM_BO_SCANOUT));
- TRACKRENDERER_ERROR_P(trackrenderer, "create new tbm %p", tbm_surf_t);
- } else {
- tbm_surf_t = static_cast<tbm_surface_h>(tbm_surf);
- }
- stream.bo[GST_VIDEO_COMP_Y] = tbm_surface_internal_get_bo(tbm_surf_t, 0);
- if (!stream.bo[GST_VIDEO_COMP_Y]) {
- TRACKRENDERER_ERROR_P(trackrenderer, "[bo Y] tbm_bo_alloc failed");
- return;
- }
- stream.bo[GST_VIDEO_COMP_U] = tbm_surface_internal_get_bo(tbm_surf_t, 1);
- if (!stream.bo[GST_VIDEO_COMP_U]) {
- TRACKRENDERER_ERROR_P(trackrenderer, "[bo U] tbm_bo_alloc failed");
- return;
- }
- if (TBM_SURFACE_ERROR_NONE !=
- tbm_surface_get_info(tbm_surf_t, &surface_info)) {
- TRACKRENDERER_ERROR_P(trackrenderer, "tbm_surface_get_info failed");
- return;
- }
- stream.stride[GST_VIDEO_COMP_Y] = surface_info.planes[0].stride;
- stream.stride[GST_VIDEO_COMP_U] = surface_info.planes[1].stride;
-
- trackrenderer->display_->GetDisplayCropArea(&crop_info);
- x = width * crop_info.scale_x;
- y = height * crop_info.scale_y;
- w = width * crop_info.scale_w;
- h = height * crop_info.scale_h;
- internal::SetGeometry(&stream.crop_area, x & 0xFFFFFFFE, y & 0xFFFFFFFE, w,
- h);
- if (!internal::ScaleHwCodecWithGa(
- trackrenderer->tbm_buffer_manager_->bufmgr, stream, y_phyaddr,
- u_phyaddr, y_linesize, c_linesize, colorformat)) {
- TRACKRENDERER_ERROR_P(trackrenderer, "data copy fail");
- return;
- }
- } else {
- TRACKRENDERER_ERROR_P(trackrenderer, "SW decoder type, not support now");
- return;
- }
- packet.pts = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer)); // ns -> ms
- packet.surface_data = tbm_surf_t;
- trackrenderer->eventlistener_->OnMediaPacketVideoDecoded(packet);
- exception_flag = false;
- return;
-}
-
-void TrackRenderer::GstAiFilterResultCb_(GstElement* element,
- GstStructure* structure,
- void* userdata) {
- auto trackrenderer = static_cast<TrackRenderer*>(userdata);
- const gchar* struct_name = gst_structure_get_name(structure);
- if (!strcmp(struct_name, "auto_zoom_crop")) {
- CropArea roi_area;
- gfloat x_ratio, y_ratio = 0.0f;
- gfloat width_ratio, height_ratio = 1.0f;
-
- gst_structure_get(structure, "x_ratio", G_TYPE_FLOAT, &x_ratio, "y_ratio",
- G_TYPE_FLOAT, &y_ratio, "width_ratio", G_TYPE_FLOAT,
- &width_ratio, "height_ratio", G_TYPE_FLOAT, &height_ratio,
- NULL);
- TRACKRENDERER_DEBUG_P(
- trackrenderer, "x_ratio %f y_ratio %f width_ratio %f height_ratio %f",
- x_ratio, y_ratio, width_ratio, height_ratio);
-
- roi_area.scale_x = (double)x_ratio;
- roi_area.scale_y = (double)y_ratio;
- roi_area.scale_w = (double)width_ratio;
- roi_area.scale_h = (double)height_ratio;
- trackrenderer->display_->SetDisplayCropArea(roi_area);
- if (!trackrenderer->pipeline_) return;
- trackrenderer->pipeline_->Execute(
- Elements::kSinkVideo, [trackrenderer](GstElement * obj) noexcept {
- return trackrenderer->display_->UpdateCropArea(obj);
- });
- }
- return;
-}
-// LCOV_EXCL_STOP
-
-void TrackRenderer::FlushAppsrc(TrackType type, bool setbyuser) {
- TRACKRENDERER_ENTER_P(this);
+void TrackRenderer::FlushAppsrc(TrackType type) {
+ TRACKRENDERER_ENTER;
if (!pipeline_) return;
- if (type >= kTrackTypeMax) {
- TRACKRENDERER_ERROR_P(
- this,
+ if (type != kTrackTypeAudio && type != kTrackTypeSubtitle &&
+ type != kTrackTypeVideo) {
+ TRACKRENDERER_ERROR(
"Support only audio and subtitle and video pipeline flush for now");
return;
}
- Track track;
- if (!track_util::GetActiveTrack(trackinfo_, type, &track)) {
- TRACKRENDERER_ERROR_P(this, "There is no %s track",
- track_util::GetTrackTypeString(type).c_str());
- return;
- }
- if (setbyuser && type == kTrackTypeAudio) enable_audio_track_change_ = true;
Elements element = Elements::kAppSrcSubtitle;
if (type == kTrackTypeAudio) {
element = Elements::kAppSrcAudio;
} else if (type == kTrackTypeVideo) {
- if (support_videodec_underflow_pause_) {
- pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
- }
element = Elements::kAppSrcVideo;
- latency_manager_->UpdateVideoFrameStatus(
- LatencyManager::UpdatePacketStatus::kFlush);
}
pipeline_->Flush(element);
- if (setbyuser) is_flushing_ = true;
+ is_flushing_ = true;
- // TODO: external flush api seems not to need to check pad idle status. it is
- // necessary to check whether to remove this code.
Pipeline<Elements>::Pad pad;
pipeline_->PadAddProbe(element, nullptr, "src", GST_PAD_PROBE_TYPE_IDLE,
GstPadProbeIdleCb_, &pad, nullptr);
std::unique_lock<std::mutex> pad_block_locker(pad.m);
if (!pad.is_idle) {
pad.cv.wait(pad_block_locker);
- TRACKRENDERER_INFO_P(this, "pad block wait end");
- }
- }
- TRACKRENDERER_LEAVE_P(this);
-}
-
-void TrackRenderer::SetVideoFrameBufferType(DecodedVideoFrameBufferType type) {
- TRACKRENDERER_ENTER_E_P(this);
- decoded_buffer_type_ = type;
- if (type == DecodedVideoFrameBufferType::kScale) {
- CreateTbmBufferManager_();
- SetPropertyForDecodedVideoBufferWithDisplay_();
- }
- if (type == DecodedVideoFrameBufferType::kReference) {
- if (vr360_ == nullptr) {
- vr360_.reset(new Vr360);
+ TRACKRENDERER_INFO("pad block wait end");
}
}
-}
-
-void TrackRenderer::SetVideoFrameBufferScaleResolution(
- const uint32_t& target_width, const uint32_t& target_height) {
- TRACKRENDERER_ENTER;
- std::lock_guard<std::mutex> lk(scale_target_m_);
- scale_target_width_ = target_width;
- scale_target_height_ = target_height;
- is_scale_size_changed_ = true;
-}
-
-bool TrackRenderer::SetDecodedVideoFrameRate(
- const Rational& request_framerate) {
- TRACKRENDERER_ENTER;
- std::lock_guard<std::mutex> lk(decoded_drop_ctx_.drop_mutex);
-
- if (request_framerate.num && !request_framerate.den) {
- TRACKRENDERER_ERROR("invalid request frame rate: %d/%d",
- request_framerate.num, request_framerate.den);
- return false;
- }
- decoded_drop_ctx_.request_fps = request_framerate;
- decoded_drop_ctx_.fps_changed = true;
- return true;
+ TRACKRENDERER_LEAVE;
}
void TrackRenderer::RegisterListener(EventListener* listener) {
}
bool TrackRenderer::RemoveDownstreamOfAppsrc_(TrackType type) {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
if (type == kTrackTypeVideo) {
- pipeline_->BinRemove(Elements::kBinVideo, Elements::kDrmVideo,
- Elements::kDecVideo, Elements::kQueueCaption,
- Elements::kSinkCaption, Elements::kAiFilter,
- Elements::kSinkVideo);
+ if (pipeline_->IsFactoryListType(Elements::kDecVideo, GST_ELEMENT_FACTORY_TYPE_HARDWARE)) {
+ pipeline_->BinRemove(Elements::kBinVideo, Elements::kDrmVideo, Elements::kParseVideo,
+ Elements::kDecVideo, Elements::kSinkVideo);
+ } else { /* sw */
+ pipeline_->BinRemove(Elements::kBinVideo, Elements::kDrmVideo, Elements::kParseVideo,
+ Elements::kDecVideo, Elements::kVideoConvert, Elements::kSinkVideo);
+ }
} else if (type == kTrackTypeAudio) {
- pipeline_->BinRemove(Elements::kBinAudio, Elements::kDrmAudio,
+ pipeline_->BinRemove(Elements::kBinAudio, Elements::kDrmAudio, Elements::kParseAudio,
Elements::kDecAudio, Elements::kAudioConvert,
Elements::kCapsFillterDefault,
Elements::kAudioResample, Elements::kCapsFillter2,
Elements::kScaleTempo, Elements::kSinkAudio);
}
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
-// LCOV_EXCL_START
GstPadProbeReturn TrackRenderer::GstPadProbeBlockCb_(GstPad* pad,
GstPadProbeInfo* info,
gpointer userdata) {
- TRACKRENDERER_ENTER_P(userdata);
+ TRACKRENDERER_ENTER;
if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
GstEvent* event = GST_PAD_PROBE_INFO_EVENT(info);
if (!GST_EVENT_IS_SERIALIZED(event)) {
- TRACKRENDERER_DEBUG_P(userdata, "pass non-serialized event");
+ TRACKRENDERER_DEBUG("pass non-serialized event");
return GST_PAD_PROBE_PASS;
}
if (GST_EVENT_IS_STICKY(event) && GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
- TRACKRENDERER_DEBUG_P(userdata, "pass sticky event");
+ TRACKRENDERER_DEBUG("pass sticky event");
return GST_PAD_PROBE_PASS;
}
}
if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_BUFFER) {
- TRACKRENDERER_DEBUG_P(userdata, "drop buffer as pad is not re-activated");
+ TRACKRENDERER_DEBUG("drop buffer as pad is not re-activated");
return GST_PAD_PROBE_DROP;
}
return GST_PAD_PROBE_OK;
}
-// LCOV_EXCL_STOP
GstPadProbeReturn TrackRenderer::GstPadProbeVideoPeekBlockCb_(
GstPad* pad, GstPadProbeInfo* info, gpointer userdata) {
- auto trackrenderer = static_cast<TrackRenderer*>(userdata);
- TRACKRENDERER_ENTER_P(trackrenderer);
+ TRACKRENDERER_ENTER;
if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
GstEvent* event = GST_PAD_PROBE_INFO_EVENT(info);
if (!GST_EVENT_IS_SERIALIZED(event)) {
- TRACKRENDERER_DEBUG_P(trackrenderer, "pass non-serialized event");
+ TRACKRENDERER_DEBUG("pass non-serialized event");
return GST_PAD_PROBE_PASS;
}
if (GST_EVENT_IS_STICKY(event) && GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
- TRACKRENDERER_DEBUG_P(trackrenderer, "pass sticky event");
+ TRACKRENDERER_DEBUG("pass sticky event");
return GST_PAD_PROBE_PASS;
}
}
GstBuffer* buffer = gst_pad_probe_info_get_buffer(info);
if (!buffer) {
- TRACKRENDERER_ERROR_P(trackrenderer, "buffer is null maybe EOS event");
+ TRACKRENDERER_ERROR("buffer is null maybe EOS event");
return GST_PAD_PROBE_PASS;
}
+ auto trackrenderer = static_cast<TrackRenderer*>(userdata);
trackrenderer->last_position_ = GST_BUFFER_PTS(buffer) / GST_MSECOND;
- TRACKRENDERER_ERROR_P(trackrenderer,
- "Update last position for playing time [%lld ms]",
- trackrenderer->last_position_);
+ TRACKRENDERER_ERROR("Update last position for playing time [%" PRIu64 "ms]",
+ trackrenderer->last_position_);
if (trackrenderer->is_seeking_ && trackrenderer->state_ == State::kWorking) {
- TRACKRENDERER_ERROR_P(trackrenderer, "Seek Done");
+ TRACKRENDERER_ERROR("Seek Done");
trackrenderer->eventlistener_->OnSeekDone();
trackrenderer->is_seeking_ = false;
return GST_PAD_PROBE_OK;
return GST_PAD_PROBE_OK;
}
-GstPadProbeReturn TrackRenderer::GstPadProbeVideoDecodedCb_(
- GstPad* pad, GstPadProbeInfo* info, gpointer userdata) {
- GstBuffer* buffer = gst_pad_probe_info_get_buffer(info);
+GstPadProbeReturn TrackRenderer::GstPadProbeAppsrcEventCb_(GstPad* pad,
+ GstPadProbeInfo* info,
+ gpointer userdata) {
auto trackrenderer = static_cast<TrackRenderer*>(userdata);
- if (trackrenderer->state_ < State::kWorking && buffer) {
- TRACKRENDERER_ERROR_P(trackrenderer, "First Decoding Done");
- trackrenderer->eventlistener_->OnFirstDecodingDone();
+ GstEvent *event = (GstEvent *)(info->data);
+ GstEvent *tmpev = nullptr;
+ GstStructure *str = nullptr;
+ const gchar *name = nullptr;
+ TrackType type = kTrackTypeMax;
+ GstSegment segment;
+
+ if (GST_EVENT_TYPE (event) != GST_EVENT_SEGMENT)
+ return GST_PAD_PROBE_PASS;
+
+ auto caps = gst_pad_has_current_caps(pad) == TRUE
+ ? gstguard::make_guard(gst_pad_get_current_caps(pad))
+ : gstguard::make_guard(gst_pad_query_caps(pad, NULL));
+ if (!caps) {
+ TRACKRENDERER_ERROR("failed to get caps");
+ return GST_PAD_PROBE_PASS;
+ }
+ str = gst_caps_get_structure(caps.get(), 0);
+ if (str)
+ name = gst_structure_get_name(str);
+ if (!str || !name) {
+ TRACKRENDERER_ERROR("failed to get caps info");
+ return GST_PAD_PROBE_PASS;
}
- return GST_PAD_PROBE_OK;
-}
-GstPadProbeReturn TrackRenderer::GstPadProbeVideoDecInputCb_(
- GstPad* pad, GstPadProbeInfo* info, gpointer userdata) {
- TRACKRENDERER_ENTER_P(userdata);
- if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_BUFFER) {
- TRACKRENDERER_ERROR_P(
- userdata, "block first video input buffer when do underflow pause");
- return GST_PAD_PROBE_OK;
- } else
+ if (strstr(name, "audio")) {
+ type = kTrackTypeAudio;
+ } else if (strstr(name, "video")) {
+ type = kTrackTypeVideo;
+ } else if (strstr(name, "text")) {
+ type = kTrackTypeSubtitle;
+ } else {
+ TRACKRENDERER_WARN("invalid name %s", name);
+ return GST_PAD_PROBE_PASS;
+ }
+
+ if (!trackrenderer->trackctx_[type].need_update_segment) {
+ TRACKRENDERER_INFO("segment is already updated");
+ return GST_PAD_PROBE_PASS;
+ }
+
+ gst_event_copy_segment(event, &segment);
+ if (segment.format != GST_FORMAT_TIME) {
+ TRACKRENDERER_WARN("segment format is not GST_FORMAT_TIME");
return GST_PAD_PROBE_PASS;
+ }
+
+ TRACKRENDERER_INFO("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
+ ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
+ ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
+ GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
+ GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
+
+ segment.time += trackrenderer->start_time;
+ segment.position += trackrenderer->start_time;
+ segment.start += trackrenderer->start_time;
+
+ TRACKRENDERER_INFO("[%d] new base: %" GST_TIME_FORMAT ", start %" GST_TIME_FORMAT,
+ type, GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.start));
+
+ tmpev = gst_event_new_segment(&segment);
+ gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
+ gst_event_unref(event);
+ GST_PAD_PROBE_INFO_DATA(info) = tmpev;
+
+ trackrenderer->trackctx_[type].need_update_segment = false;
+
+ return GST_PAD_PROBE_OK;
}
+
bool TrackRenderer::Deactivate(TrackType type) {
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
if (state_ == State::kStopped) return false;
if (!pipeline_) return false;
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
Track track;
if (!track_util::GetActiveTrack(trackinfo_, type, &track)) {
- TRACKRENDERER_ERROR_P(this, "There is no track to deactivate");
+ TRACKRENDERER_ERROR("There is no track to deactivate");
return false;
}
- if (type >= kTrackTypeMax) return false;
+
trackctx_[type].index = kInvalidTrackIndex;
if (type == kTrackTypeVideo) {
pipeline_->PadAddProbe(Elements::kAppSrcVideo, kPadProbeVideoBlock, "src",
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
GstPadProbeBlockCb_, nullptr, nullptr);
pipeline_->SetProperty(Elements::kSinkVideo, "async", FALSE);
- FlushAppsrc(type, false);
+
+ FlushAppsrc(type);
RemoveDownstreamOfAppsrc_(type);
- auto is_video_track = [](const Track& item) -> bool {
+ auto is_video_track = [](Track item) -> bool {
return item.type == kTrackTypeVideo;
};
auto target =
if (target != trackinfo_.end()) {
trackinfo_.erase(target);
}
- resource_manager_->Dealloc(video_decoder_id_);
- resource_manager_->Dealloc(video_renderer_id_);
+ resource_manager_->Release(ResourceCategory::kVideoDecoder);
+ resource_manager_->Release(ResourceCategory::kVideoRenderer);
} else if (type == kTrackTypeAudio) {
pipeline_->PadAddProbe(Elements::kAppSrcAudio, kPadProbeAudioBlock, "src",
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
GstPadProbeBlockCb_, nullptr, nullptr);
- pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
- FlushAppsrc(type, false);
+ /* FIXME: check why block here */
+ FlushAppsrc(type);
RemoveDownstreamOfAppsrc_(type);
-
- auto is_audio_track = [](const Track& item) -> bool {
+ auto is_audio_track = [](Track item) -> bool {
return item.type == kTrackTypeAudio;
};
auto target =
if (target != trackinfo_.end()) {
trackinfo_.erase(target);
}
- resource_manager_->Dealloc(audio_decoder_id_);
- resource_manager_->Dealloc(audio_out_id_);
- if (!AvocPlayerUnRegister_()) return false;
} else {
pipeline_->PadAddProbe(Elements::kAppSrcSubtitle, kPadProbeSubtitleBlock,
"src", GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, nullptr,
nullptr, nullptr);
- FlushAppsrc(type, false);
+ FlushAppsrc(type);
- auto is_subtitle_track = [](const Track& item) -> bool {
+ auto is_subtitle_track = [](Track item) -> bool {
return item.type == kTrackTypeSubtitle;
};
auto target =
trackinfo_.erase(target);
}
}
- TRACKRENDERER_LEAVE_P(this);
+
+ TRACKRENDERER_LEAVE;
return true;
}
-bool TrackRenderer::Activate(TrackType type, const Track& track) {
- // construct pipeline
- TRACKRENDERER_ENTER_P(this);
- std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
- if (state_ == State::kStopped) return false;
- if (!pipeline_) return false;
+bool TrackRenderer::ActivateAudioPipeline(GstCaps * caps) {
+ TRACKRENDERER_ENTER;
+ pipeline_->FactoryMake(Elements::kParseAudio, caps,
+ GST_ELEMENT_FACTORY_TYPE_PARSER, NULL);
- Track active_track;
- if (type >= kTrackTypeMax) return false;
- if (trackctx_[type].track &&
- track_util::GetActiveTrack(trackinfo_, type, &active_track)) {
- TRACKRENDERER_ERROR_P(this,
- "Valid and activated track, can not be activated.");
+ auto parse_caps =
+ gstguard::make_guard(pipeline_->GetSrcPadCaps(Elements::kParseAudio));
+ auto parse_caps_str = gstguard::make_guard(gst_caps_to_string(parse_caps.get()));
+ TRACKRENDERER_INFO("parse caps %s", parse_caps_str.get());
+
+ if (!pipeline_->FactoryMake(Elements::kDecAudio, (GstCaps*)parse_caps.get(),
+ GST_ELEMENT_FACTORY_TYPE_DECODER, NULL)) {
+ const ErrorType err = ErrorType::kNotSupportedAudioCodec;
+ eventlistener_->OnError(err);
return false;
}
- if (!trackctx_[type].track) {
- TRACKRENDERER_INFO_P(this, "Add a new stream.");
- if (type == kTrackTypeAudio) {
- CreateAppSrc_(kTrackTypeAudio, track.mimetype);
- pipeline_->SetProperty(Elements::kAppSrcAudio, "update-segment",
- rendering_start_time_.time);
- pipeline_->CreateBin(Elements::kBinAudio, "audiobin");
- pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinAudio);
- pipeline_->BinAdd(Elements::kBinAudio, Elements::kAppSrcAudio);
- } else if (type == kTrackTypeVideo) {
- CreateAppSrc_(kTrackTypeVideo, track.mimetype);
- pipeline_->SetProperty(Elements::kAppSrcVideo, "update-segment",
- rendering_start_time_.time);
- pipeline_->CreateBin(Elements::kBinVideo, "videobin");
- pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinVideo);
- pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo);
- } else if (type == kTrackTypeSubtitle) {
- TRACKRENDERER_INFO_P(this,
- "set subtitle track information in track renderer");
- trackctx_[type].index = track.index;
- trackinfo_.push_back(track);
- trackctx_[track.type].track = &(trackinfo_.back());
- return true;
- }
- }
+ pipeline_->FactoryMake(Elements::kAudioConvert, "audioconvert", nullptr);
+ pipeline_->FactoryMake(Elements::kAudioResample, "audioresample", nullptr);
+ pipeline_->FactoryMake(
+ Elements::kSinkAudio,
+ "pulsesink",
+ nullptr);
- trackctx_[type].index = track.index;
- trackinfo_.push_back(track);
- trackctx_[track.type].track = &(trackinfo_.back());
+ pipeline_->SetProperty(Elements::kSinkAudio, "sync", TRUE, "async", TRUE, "provide-clock", FALSE);
+ pipeline_->SetProperty(Elements::kAppSrcAudio, "stream-type",
+ GST_APP_STREAM_TYPE_SEEKABLE);
+ pipeline_->SetProperty(Elements::kAppSrcAudio, "format", GST_FORMAT_TIME);
- if (type == kTrackTypeAudio) {
- if (!AvocPlayerRegister_()) {
- TRACKRENDERER_ERROR_P(this, "AvocPlayerRegister_() fail.");
- return false;
- }
- }
- if (!GetResource_(track.type)) {
- TRACKRENDERER_ERROR_P(this,
- "[%s] resource allocation fail! ChangeTrack fail.",
- track_util::GetTrackTypeString(track.type).c_str());
- return false;
- }
- if (type == kTrackTypeVideo) {
- // the element name should be changed
- CreateDrmElement_(track);
-
- const char* kDecoderPluginName =
- GetDecoderPluginName_(kTrackTypeVideo, track.mimetype);
- if (kDecoderPluginName &&
- (strcmp(kDecoderPluginName, kSkippedResource) == 0)) {
- const ErrorType err = ErrorType::kResourceLimit;
- eventlistener_->OnError(err);
- eventlistener_->OnErrorMsg(err,
- const_cast<char*>(track.mimetype.c_str()));
- return false;
- }
- CreateVideoDecoder_(kDecoderPluginName);
+ pipeline_->BinAdd(Elements::kBinAudio,
+ Elements::kParseAudio, Elements::kDecAudio,
+ Elements::kAudioConvert, Elements::kAudioResample,
+ Elements::kSinkAudio);
+
+ pipeline_->PadRemoveProbe(kPadProbeAudioBlock);
+
+ TRACKRENDERER_LEAVE;
+ UpdatePlaybackInfo_(true);
+
+ return true;
+}
+
+GstPadProbeReturn TrackRenderer::GstPadProbeCapsEventCb_(GstPad* pad,
+ GstPadProbeInfo* info,
+ gpointer userdata) {
+ auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+
+ if (GST_EVENT_TYPE (info->data) == GST_EVENT_CAPS) {
+ GstCaps *caps;
- if (CreateVideoSink_() == false) return false;
+ gst_event_parse_caps ((GstEvent*)(info->data), &caps);
+ auto caps_str = gstguard::make_guard(gst_caps_to_string(caps));
- GstElementLowLatency_(kTrackTypeVideo);
+ TRACKRENDERER_INFO("caps %s", caps_str.get());
- SetPropertyForAiFilter_();
+ trackrenderer->ActivateAudioPipeline(caps);
+ return GST_PAD_PROBE_REMOVE;
+ }
+
+ return GST_PAD_PROBE_PASS;
+}
- if (internal::IsDisplayNeeded(display_type_)) {
- pipeline_->Execute(
- Elements::kSinkVideo,
- [this](GstElement * obj) noexcept { return display_->Update(obj); });
+bool TrackRenderer::Activate(TrackType type, const Track& track) {
+ // construct pipeline
+ TRACKRENDERER_ENTER;
+ std::lock_guard<std::mutex> lk(resource_m_);
+ if (state_ == State::kStopped) return false;
+ if (!pipeline_) return false;
+
+ Track active_track;
+ if (!trackctx_[type].track ||
+ track_util::GetActiveTrack(trackinfo_, type, &active_track)) {
+ // Fix:: for external subtitle case, it may possible subtitle tracksource
+ // prepared after main tracksource should be allowed to set subtitle current
+ // track information in renderer trackctx_ so that it can be submitted to
+ // subtitle renderer pipeline.
+ if (type == kTrackTypeSubtitle) {
+ TRACKRENDERER_ERROR("set subtitle track information in track renderer");
+ trackctx_[type].index = track.index;
+ trackinfo_.push_back(track);
+ return true;
}
- gboolean is_async = FALSE;
- pipeline_->GetProperty(Elements::kSinkVideo, "async", &is_async);
- if (is_async) pipeline_->SetProperty(Elements::kSinkVideo, "async", FALSE);
+ TRACKRENDERER_ERROR("Only valid but deactivated track can be activated.");
+ return false;
+ }
- pipeline_->BinAdd(Elements::kBinVideo, Elements::kDrmVideo,
- Elements::kDecVideo, Elements::kAiFilter,
- Elements::kSinkVideo);
+ trackctx_[type].index = track.index;
+ TRACKRENDERER_INFO("track type %d, index %d", type, track.index);
- if (is_async) pipeline_->SetProperty(Elements::kSinkVideo, "async", TRUE);
+ trackinfo_.push_back(track);
+ if (type == kTrackTypeVideo) {
+ if (!internal::IsSdkEnabledFeature() && !track.use_swdecoder) { /* except sw */
+ std::list<ResourceProperty> propertylist;
+ ResourceProperty videodecproperty;
+ videodecproperty.category = ResourceCategory::kVideoDecoder;
+ videodecproperty.track = track;
+ propertylist.push_back(videodecproperty);
+
+ ResourceProperty videorenderproperty;
+ videorenderproperty.category = ResourceCategory::kVideoRenderer;
+ propertylist.push_back(videorenderproperty);
+
+ if (!resource_manager_->Acquire(propertylist)) {
+ TRACKRENDERER_ERROR("Video resource acquire fail! ChangeTrack fail.");
+ return false;
+ }
+ }
auto caps = caps_builder_.Build(track, internal::IsDrmEmeElementNecessary(
drm_property_, track.mimetype));
+ pipeline_->FactoryMake(Elements::kDecVideo, (GstCaps*)caps.GetCaps_(),
+ GST_ELEMENT_FACTORY_TYPE_DECODER, NULL);
+ pipeline_->FactoryMake(Elements::kSinkVideo,
+ internal::GetVideoSinkPluginName(ini_elements_,
+ track.use_swdecoder), NULL);
+ pipeline_->SetProperty(Elements::kSinkVideo, "async", FALSE);
+ pipeline_->SetProperty(Elements::kSinkVideo, "use-seq-mode", use_seq_mode_);
+ if (internal::IsDecryptorElementNecessary(drm_property_)) {
+ pipeline_->FactoryMake(Elements::kDrmVideo, "cencdecrypt", NULL);
+ pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-cb",
+ GstVideoDrmInitDataCb_);
+ pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-cb-data",
+ this);
+ }
+
+ pipeline_->BinAdd(Elements::kBinVideo, Elements::kDrmVideo,
+ Elements::kDecVideo, Elements::kSinkVideo);
+
+ pipeline_->SetProperty(Elements::kSinkVideo, "sync", TRUE, "async", TRUE);
pipeline_->SetAppSrcCaps(Elements::kAppSrcVideo, caps);
- SetPropertyForDecodedVideoBuffer_();
pipeline_->PadRemoveProbe(kPadProbeVideoBlock);
+ pipeline_->Execute(Elements::kSinkVideo, [this](GstElement* obj) noexcept {
+ return display_->Update(obj);
+ });
UpdatePlaybackInfo_(true);
- UpdateTrackFrameRate_(track.framerate_num, track.framerate_den);
} else if (type == kTrackTypeAudio) {
// the element name should be changed
- CreateDrmElement_(track);
- if (internal::IsDecoderElementNecessary(track.mimetype)) {
- const char* kDecoderPluginName =
- GetDecoderPluginName_(kTrackTypeAudio, track.mimetype);
- pipeline_->FactoryMake(Elements::kDecAudio, kDecoderPluginName, nullptr);
- if (internal::IsHwPlugin(kDecoderPluginName)) {
- if (low_latency_mode_ ==
- static_cast<std::uint32_t>(LowLatencyMode::kLowLatencyModeNone)) {
- constexpr int kPtsManipulationThreshold = 99000; // 99ms
- pipeline_->SetProperty(Elements::kDecAudio, "set-usr-cal-timestamp",
- kPtsManipulationThreshold);
- }
- pipeline_->SetProperty(Elements::kDecAudio, "support-codec-change",
- support_audio_codec_change_);
+ if (internal::IsDrmEmeElementNecessary(drm_property_, track.mimetype)) {
+ pipeline_->FactoryMake(Elements::kDrmAudio, "drm_eme", "audio_drm");
+ pipeline_->SetProperty(Elements::kDrmAudio, "plus-player-eme", TRUE);
+ if (internal::IsExternalDecryptionCase(drm_property_) == false) {
+ pipeline_->SetProperty(Elements::kDrmAudio, "getrights-complete-cb",
+ GstAudioDrmInitDataCb_);
+ pipeline_->SetProperty(Elements::kDrmAudio,
+ "getrights-complete-cb-data", this);
}
}
- std::string audiosink_name =
- GetAudioSinkPluginName_(track.use_swdecoder, track.mimetype);
- CreateAudioSink_(audiosink_name);
-
- AvocPlayRequest_();
- SetAudioOut_();
- GstElementLowLatency_(kTrackTypeAudio);
- gboolean is_async = FALSE;
- pipeline_->GetProperty(Elements::kSinkAudio, "async", &is_async);
- if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
+ auto current_caps =
+ gstguard::make_guard(pipeline_->GetSrcPadCaps(Elements::kAppSrcAudio));
+ auto cur_caps_str = gstguard::make_guard(gst_caps_to_string(current_caps.get()));
+ TRACKRENDERER_INFO("old caps %s", cur_caps_str.get());
- pipeline_->BinAdd(Elements::kBinAudio, Elements::kDrmAudio,
- Elements::kDecAudio, Elements::kAudioConvert,
- Elements::kCapsFillterDefault, Elements::kAudioResample,
- Elements::kCapsFillter2, Elements::kScaleTempo,
- Elements::kSinkAudio);
- if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", TRUE);
+ auto new_caps = caps_builder_.Build(track, false);
+ auto new_caps_str = gstguard::make_guard(gst_caps_to_string(new_caps.GetCaps_()));
+ TRACKRENDERER_INFO("new caps %s", new_caps_str.get());
- auto caps = caps_builder_.Build(track, internal::IsDrmEmeElementNecessary(
- drm_property_, track.mimetype));
- pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
- pipeline_->PadRemoveProbe(kPadProbeAudioBlock);
- UpdatePlaybackInfo_(true);
+ gboolean caps_changed = !gst_caps_is_equal (new_caps.GetCaps_(), current_caps.get());
+ if (caps_changed) { // caps is different
+ TRACKRENDERER_INFO("Caps is changed");
+ pipeline_->PadAddProbe(Elements::kAppSrcAudio, kPadProbeCapsEvent, "src",
+ (GstPadProbeType)(GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM),
+ GstPadProbeCapsEventCb_, this, nullptr);
+ pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, new_caps);
+ } else {
+ TRACKRENDERER_INFO("Caps is the same");
+ ActivateAudioPipeline((GstCaps*)new_caps.GetCaps_());
+ }
} else {
auto caps =
gstguard::make_guard(gst_caps_new_empty_simple(track.mimetype.c_str()));
pipeline_->SetProperty(Elements::kAppSrcSubtitle, "caps", caps.get());
pipeline_->PadRemoveProbe(kPadProbeSubtitleBlock);
}
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
return true;
}
: (pos_video / GST_MSECOND);
else
*curtime_in_msec = last_position_;
- // TRACKRENDERER_INFO_P(this, "playing time [%llu ms]", *curtime_in_msec);
+ // TRACKRENDERER_INFO("playing time [%" PRIu64 " ms]", *curtime_in_msec);
return true;
}
return false;
}
-bool TrackRenderer::GetDroppedFramesForCatchup(TrackType type,
- void* frame_counts) {
- std::lock_guard<std::mutex> lk(resource_m_);
- if (state_ == State::kStopped) return false;
- if (!pipeline_) return false;
- uint64_t drop_count = 0;
- Elements video_element = Elements::kSinkVideo;
- Elements audio_element = Elements::kSinkAudio;
- bool ret = false;
-
- if (type == kTrackTypeAudio) {
- ret = pipeline_->GetProperty(audio_element, "dropped-frames-for-catchup",
- &drop_count);
- } else if (type == kTrackTypeVideo) {
- ret = pipeline_->GetProperty(video_element, "dropped-frames-for-catchup",
- &drop_count);
- }
-
- if (ret) {
- *(int64_t*)frame_counts = drop_count;
- return true;
- }
-
- return false;
-}
-
bool TrackRenderer::SetDisplayMode(const DisplayMode& mode) {
std::lock_guard<std::mutex> lk(resource_m_);
if (state_ == State::kStopped) return false;
display_->SetDisplayMode(mode);
if (!pipeline_) return true;
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+ pipeline_->Execute(Elements::kSinkVideo, [this](GstElement* obj) noexcept {
return display_->Update(obj);
});
return true;
if (state_ == State::kStopped) return false;
display_->SetDisplayRotate(rotate);
if (!pipeline_) return true;
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+ pipeline_->Execute(Elements::kSinkVideo, [this](GstElement* obj) noexcept {
return display_->Update(obj);
});
return true;
bool TrackRenderer::SetDisplay(const DisplayType& type, void* obj) {
std::lock_guard<std::mutex> lk(resource_m_);
if (state_ == State::kStopped) return false;
- display_type_ = type;
- if (type == DisplayType::kNone) {
- TRACKRENDERER_WARN_P(this, "Just Reset Display type as None");
- return true;
- }
display_->SetDisplay(type, static_cast<Evas_Object*>(obj));
-
if (!pipeline_) return true;
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * _obj) noexcept {
- return display_->Update(_obj);
+ pipeline_->Execute(Elements::kSinkVideo, [this](GstElement* obj) noexcept {
+ return display_->Update(obj);
});
return true;
}
-// LCOV_EXCL_START
bool TrackRenderer::SetDisplay(const DisplayType& type, void* ecore_wl2_window,
int x, int y, int w, int h) {
std::lock_guard<std::mutex> lk(resource_m_);
if (state_ == State::kStopped) return false;
- display_type_ = type;
display_->SetDisplay(type, static_cast<Ecore_Wl2_Window*>(ecore_wl2_window),
x, y, w, h);
if (!pipeline_) return true;
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
- return display_->Update(obj);
- });
- return true;
-}
-// LCOV_EXCL_STOP
-
-bool TrackRenderer::SetDisplaySubsurface(const DisplayType& type,
- void* ecore_wl2_subsurface, int x,
- int y, int w, int h) {
- std::lock_guard<std::mutex> lk(resource_m_);
- if (state_ == State::kStopped) return false;
- display_type_ = type;
- display_->SetDisplaySubsurface(
- type, static_cast<Ecore_Wl2_Subsurface*>(ecore_wl2_subsurface), x, y, w,
- h);
- if (!pipeline_) return true;
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+ pipeline_->Execute(Elements::kSinkVideo, [this](GstElement* obj) noexcept {
return display_->Update(obj);
});
return true;
}
void TrackRenderer::DrmLicenseAcquiredDone(TrackType type) {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
if (type == kTrackTypeAudio) {
pipeline_->SetProperty(Elements::kDrmAudio, "getrights-complete-return",
TRUE);
pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-return",
TRUE);
} else {
- TRACKRENDERER_ERROR_P(this, "Invalid Track Type !!");
+ TRACKRENDERER_ERROR("Invalid Track Type !!");
}
- TRACKRENDERER_LEAVE_P(this);
+ TRACKRENDERER_LEAVE;
+}
+
+void TrackRenderer::SetDrmLicenseKey(TrackType type, const std::string& key) {
+ TRACKRENDERER_ENTER;
+ if (type == kTrackTypeAudio) {
+ pipeline_->SetProperty(Elements::kDrmAudio, "setright-key",
+ key.c_str());
+ } else if (type == kTrackTypeVideo) {
+ pipeline_->SetProperty(Elements::kDrmVideo, "setright-key",
+ key.c_str());
+ } else {
+ TRACKRENDERER_ERROR("Invalid Track Type !!");
+ }
+ TRACKRENDERER_LEAVE;
}
bool TrackRenderer::SetDisplay(const DisplayType& type, unsigned int surface_id,
long x, long y, long w, long h) {
std::lock_guard<std::mutex> lk(resource_m_);
if (state_ == State::kStopped) return false;
- display_type_ = type;
display_->SetDisplay(type, surface_id, x, y, w, h);
if (!pipeline_) return true;
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+ pipeline_->Execute(Elements::kSinkVideo, [this](GstElement* obj) noexcept {
return display_->Update(obj);
});
return true;
if (state_ == State::kStopped) return false;
display_->SetDisplayRoi(roi);
if (!pipeline_) return true;
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+ pipeline_->Execute(Elements::kSinkVideo, [this](GstElement* obj) noexcept {
return display_->Update(obj);
});
return true;
if (state_ == State::kStopped) return false;
display_->SetDisplayCropArea(area);
if (!pipeline_) return true;
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
- return display_->UpdateCropArea(obj);
- });
- return true;
-}
-
-bool TrackRenderer::ResizeRenderRect(const RenderRect& rect) {
- std::lock_guard<std::mutex> lk(resource_m_);
- if (state_ == State::kStopped) return false;
- display_->ResizeRenderRect(rect);
- if (!pipeline_) return true;
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+ pipeline_->Execute(Elements::kSinkVideo, [this](GstElement* obj) noexcept {
return display_->Update(obj);
});
return true;
}
bool TrackRenderer::SetDisplayVisible(bool is_visible) {
- TRACKRENDERER_DEBUG_P(this, "visible: %d", is_visible);
+ TRACKRENDERER_DEBUG("visible: %d", is_visible);
std::lock_guard<std::mutex> lk(resource_m_);
if (state_ == State::kStopped) return false;
display_->SetVisible(is_visible);
if (pipeline_ == nullptr) return true;
- pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+ pipeline_->Execute(Elements::kSinkVideo, [this](GstElement* obj) noexcept {
return display_->UpdateVisible(obj);
});
return true;
}
bool TrackRenderer::SetAudioMute(bool is_mute) {
- TRACKRENDERER_DEBUG_P(this, "mute: %d", is_mute);
+ TRACKRENDERER_DEBUG("mute: %d", is_mute);
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
if (state_ == State::kStopped) return false;
- is_sound_mute_ = is_mute ? TRUE : FALSE;
+ is_sound_mute_ = is_mute;
if (!pipeline_) return true;
- pipeline_->SetProperty(Elements::kSinkAudio, "mute", is_sound_mute_);
+ pipeline_->SetProperty(Elements::kSinkAudio, "mute", is_mute);
return true;
}
bool TrackRenderer::SetVolume(const int& volume) {
- TRACKRENDERER_DEBUG_P(this, "volume: %d", volume);
+ TRACKRENDERER_DEBUG("volume: %d", volume);
if (volume < kVolumeMin || volume > kVolumeMax) {
- TRACKRENDERER_ERROR_P(this, "volume: %d", volume);
+ TRACKRENDERER_ERROR("volume: %d", volume);
return false;
}
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
volume_ = volume;
if (!pipeline_) return true;
SetVolume_();
const gchar* sink_name = nullptr;
pipeline_->GetProperty(Elements::kSinkAudio, "name", &sink_name);
if (sink_name == nullptr) {
- TRACKRENDERER_WARN_P(this, "no audio sink");
+ TRACKRENDERER_WARN("no audio sink");
return;
}
if (strstr(sink_name, "mmaudiosink")) { // mmaudiosink or mmaudiosink2
} else if (strstr(sink_name, "alsasink")) {
pipeline_->SetProperty(Elements::kSinkAudio, "alsa-volume", volume_);
} else if (strstr(sink_name, "pulsesink")) {
- TRACKRENDERER_DEBUG_P(this, "pulsesink, not set volume");
+ TRACKRENDERER_DEBUG("pulsesink, not set volume");
} else {
- TRACKRENDERER_WARN_P(this, "unknow audio sink name: %s", sink_name);
+ TRACKRENDERER_WARN("unknow audio sink name: %s", sink_name);
}
}
-void TrackRenderer::CreateTbmBufferManager_() {
- TRACKRENDERER_ENTER_P(this);
- std::lock_guard<std::mutex> lk(tbmmgr_m_);
- if (tbm_buffer_manager_ == nullptr) {
- tbm_buffer_manager_.reset(new TbmBufferManager);
- }
-}
-
-void TrackRenderer::SetVr360GpuModeSecure_(bool set) {
- // Fix:: This is adding for Youtube 360 playback, at the beginning playback,
- // need to set GPU secure mode, when playback is finished, need to set
- // GPU non secure mode ,kReference only be set for Youtube 360 feature.
- if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kReference) {
- TRACKRENDERER_INFO_P(this, "gpu mode: [%s]", set ? "secure" : "non-secure");
- vr360_->Vr360TzSetGpuMode(set);
- }
+void TrackRenderer::CreateTbmBufferManager_(const Track* track) {
+ TRACKRENDERER_ENTER;
+ tbm_buffer_manager_.reset(new TbmBufferManager);
}
bool TrackRenderer::GetVolume(int* volume) {
return true;
}
-const char* TrackRenderer::GetDecoderPluginName_(TrackType type,
- const std::string& mimetype) {
- if (type == kTrackTypeAudio) {
- if (resource_manager_->GetAllocatedState(audio_decoder_id_) ==
- AllocatedState::kSkipped ||
- resource_manager_->GetAllocatedState(audio_out_id_) ==
- AllocatedState::kSkipped) {
- resource_manager_->Dealloc(audio_decoder_id_);
- resource_manager_->Dealloc(audio_out_id_);
- return kSkippedResource;
- }
- if (product_cfg::GetProductType() == ProductType::kAv) {
- if (internal::IsTzDecoderElementNecessary(drm_property_, mimetype))
- return "omx_tz_mmaudiodec";
- return "omx_mmaudiodec";
- }
- const std::string comp_name =
- resource_manager_->GetComponentName(audio_decoder_id_);
- if (comp_name.empty()) {
- TRACKRENDERER_ERROR_P(this, "Not found component name");
- return nullptr;
- }
- auto is_audio_track = [](const Track& item) noexcept->bool {
- return item.mimetype.find("audio") != std::string::npos;
- };
- auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
- if (target == trackinfo_.end()) {
- TRACKRENDERER_ERROR_P(this, "Not found audio track");
- return nullptr;
- }
- TRACKRENDERER_INFO_P(this, "mime type : %s", (target->mimetype).c_str());
- if (comp_name == kSwDecoderComponentName) {
- return ::kSwPluginMap.count({target->mimetype, target->version}) > 0
- ? ::kSwPluginMap.at({target->mimetype, target->version})
- .c_str()
- : nullptr;
- } else {
- return ::PluginTable.count({comp_name, target->mimetype}) > 0
- ? ::PluginTable.at({comp_name, target->mimetype}).c_str()
- : nullptr;
- }
-
- } else if (type == kTrackTypeVideo) {
- if (resource_manager_->GetAllocatedState(video_decoder_id_) ==
- AllocatedState::kSkipped ||
- resource_manager_->GetAllocatedState(video_renderer_id_) ==
- AllocatedState::kSkipped) {
- resource_manager_->Dealloc(video_decoder_id_);
- resource_manager_->Dealloc(video_renderer_id_);
- return kSkippedResource;
- }
- const std::string comp_name =
- resource_manager_->GetComponentName(video_decoder_id_);
- if (comp_name.empty()) {
- TRACKRENDERER_ERROR_P(this, "Not found component name");
- return nullptr;
- }
- auto is_video_track = [](const Track& item) noexcept->bool {
- return item.mimetype.find("video") != std::string::npos;
- };
- auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_video_track);
- if (target == trackinfo_.end()) {
- TRACKRENDERER_ERROR_P(this, "Not found video track");
- return nullptr;
- }
- TRACKRENDERER_INFO_P(this, "mime type : %s", (target->mimetype).c_str());
- if (internal::CheckMpeg4Video(target->mimetype, target->version)) {
- return ::kMpeg4VidoePluginMap.at({comp_name, target->mimetype}).c_str();
- }
- if (comp_name == kSwDecoderComponentName) {
- return ::kSwPluginMap.count({target->mimetype, target->version}) > 0
- ? ::kSwPluginMap.at({target->mimetype, target->version})
- .c_str()
- : nullptr;
- } else {
- return ::PluginTable.count({comp_name, target->mimetype}) > 0
- ? ::PluginTable.at({comp_name, target->mimetype}).c_str()
- : nullptr;
- }
- }
-
- return nullptr;
-}
-
void TrackRenderer::GetDisplay(DisplayType* type, Geometry* area) {
display_->GetDisplay(type, area);
}
}
bool TrackRenderer::RenderVideoFrame() {
- TRACKRENDERER_ENTER_P(this);
+ TRACKRENDERER_ENTER;
if (!is_video_frame_peek_) return false;
pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
return true;
}
-bool TrackRenderer::SetAiFilter(void* aifilter) {
- TRACKRENDERER_ENTER_P(this);
- return AddAiFilter_(aifilter);
-}
-
-void TrackRenderer::SetVideoMidLatencyThreshold(const unsigned int threshold) {
- TRACKRENDERER_ENTER_P(this);
- latency_manager_->SetVideoMidLatencyThreshold(threshold);
-}
-
-void TrackRenderer::SetAudioMidLatencyThreshold(const unsigned int threshold) {
- TRACKRENDERER_ENTER_P(this);
- latency_manager_->SetAudioMidLatencyThreshold(threshold);
-}
-
-void TrackRenderer::SetVideoHighLatencyThreshold(const unsigned int threshold) {
- TRACKRENDERER_ENTER_P(this);
- latency_manager_->SetVideoHighLatencyThreshold(threshold);
-}
-
-void TrackRenderer::SetAudioHighLatencyThreshold(const unsigned int threshold) {
- TRACKRENDERER_ENTER_P(this);
- latency_manager_->SetAudioHighLatencyThreshold(threshold);
-}
-
-void TrackRenderer::SetCatchUpSpeed(const CatchUpSpeed& level) {
- TRACKRENDERER_ENTER_P(this);
- latency_manager_->SetCatchUpSpeed(level);
-}
-
-void TrackRenderer::GetVideoLatencyStatus(LatencyStatus* status) {
- TRACKRENDERER_ENTER_P(this);
- latency_manager_->GetVideoLatencyStatus(status);
-}
-
-void TrackRenderer::GetAudioLatencyStatus(LatencyStatus* status) {
- TRACKRENDERER_ENTER_P(this);
- latency_manager_->GetAudioLatencyStatus(status);
-}
-
void TrackRenderer::SetAttribute_(const TrackRendererAttributeBinder& binder,
const boost::any& original_value,
const boost::any& new_value) {
TrackRendererAttributeSetter commiiter(pipeline_, binder);
bool is_set = binder.on_attribute_set(commiiter, original_value, new_value);
- TRACKRENDERER_DEBUG_P(this, "a property(prop[%s] of elem[%d]) is_set[%d]",
- binder.property.c_str(),
- static_cast<int>(binder.element), is_set);
+ TRACKRENDERER_DEBUG("a property(prop[%s] of elem[%d]) is_set[%d]",
+ binder.property.c_str(), static_cast<int>(binder.element),
+ is_set);
}
void TrackRenderer::SetAttribute(const Attribute& attr,
const boost::any& value) {
const TrackRendererAttributeBinder& binder = kAttributes_.at(attr);
if (binder.value_type != value.type()) {
- TRACKRENDERER_ERROR_P(this,
- "a property(prop[%s] of elem[%d]) type mismatched! "
- "it wasn't able to be applied.",
- binder.property.c_str(),
- static_cast<int>(binder.element));
+ TRACKRENDERER_ERROR(
+ "a property(prop[%s] of elem[%d]) type mismatched! "
+ "it wasn't able to be applied.",
+ binder.property.c_str(), static_cast<int>(binder.element));
return;
}
SetAttribute_(binder, set_attribute_values_[attr], value);
TrackRendererAttributeGetter commiiter(pipeline_, binder);
bool is_get = binder.on_attribute_get(commiiter, value);
if (!is_get)
- TRACKRENDERER_ERROR_P(this, "property(prop[%s] of elem[%d]) get failed!!!",
- binder.property.c_str(),
- static_cast<int>(binder.element));
+ TRACKRENDERER_ERROR("property(prop[%s] of elem[%d]) get failed!!!",
+ binder.property.c_str(),
+ static_cast<int>(binder.element));
}
void TrackRenderer::SetConfig(const std::string name, const boost::any& value) {
Config_Setter setter = config_setter_table_.at(name);
setter(value);
} else {
- TRACKRENDERER_ERROR_P(this,
- "No name of setter [%s], if needed, assign setter in "
- "config_setter_table & init",
- name.c_str());
+ TRACKRENDERER_ERROR(
+ "No name of setter [%s], if needed, assign setter in "
+ "config_setter_table & init",
+ name.c_str());
}
}
&TrackRenderer::SetStartRenderingTime_, this, std::placeholders::_1);
config_setter_table_[ConfigNameFmmMode] =
std::bind(&TrackRenderer::SetFmmMode_, this, std::placeholders::_1);
- config_setter_table_[ConfigNameAlternativeVideoResource] =
- std::bind(&TrackRenderer::SetAlternativeVideoResource_, this,
- std::placeholders::_1);
- config_setter_table_[ConfigNameVideoDecodingMode] = std::bind(
- &TrackRenderer::SetVideoDecodingMode_, this, std::placeholders::_1);
- config_setter_table_[ConfigNameLateVideoFrameDropMode] = std::bind(
- &TrackRenderer::SetLateVideoFrameDropMode_, this, std::placeholders::_1);
}
-// LCOV_EXCL_START
bool TrackRenderer::SetAccurateSeekMode_(const boost::any& value) {
std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+ TRACKRENDERER_ERROR(" Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
is_accurate_seek_ = (val != 0) ? true : false;
return true;
}
-// LCOV_EXCL_STOP
bool TrackRenderer::SetLowLatencyMode_(const boost::any& value) {
std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, " Mode [%d]", val);
+ TRACKRENDERER_ERROR(" Mode [%d]", val);
low_latency_mode_ = val;
- if (low_latency_mode_ & kLowLatencyModeDisableAVSync)
- unlimited_max_buffer_mode_ = true;
return true;
}
-// LCOV_EXCL_START
bool TrackRenderer::SetWindowStandAloneMode_(const boost::any& value) {
std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
- window_stand_alone_mode_ = (val != 0) ? TRUE : FALSE;
+ TRACKRENDERER_ERROR(" Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+ window_stand_alone_mode_ = (val != 0) ? true : false;
return true;
}
-// LCOV_EXCL_STOP
bool TrackRenderer::SetVideoFramePeekMode_(const boost::any& value) {
std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+ TRACKRENDERER_ERROR(" Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
is_video_frame_peek_ = (val != 0) ? true : false;
return true;
}
-// LCOV_EXCL_START
bool TrackRenderer::SetUnlimitedMaxBufferMode_(const boost::any& value) {
std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+ TRACKRENDERER_ERROR(" Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
unlimited_max_buffer_mode_ = (val != 0) ? true : false;
return true;
}
bool TrackRenderer::SetVideoPreDisplayMode_(const boost::any& value) {
std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+ TRACKRENDERER_ERROR(" Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
video_pre_display_mode_ = (val != 0) ? true : false;
return true;
}
-// LCOV_EXCL_STOP
bool TrackRenderer::SetStartRenderingTime_(const boost::any& value) {
std::uint64_t val = boost::any_cast<std::uint64_t>(value);
- TRACKRENDERER_ERROR_P(this, "time [%llu ms]", val);
+ TRACKRENDERER_ERROR("time [%" PRIu64 " ms]", val);
rendering_start_time_.is_set = true;
rendering_start_time_.time = val * GST_MSECOND;
return true;
}
-
-// LCOV_EXCL_START
bool TrackRenderer::SetFmmMode_(const boost::any& value) {
std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
- fmm_mode_ = (val != 0) ? 1 : 0;
- return true;
-}
-
-bool TrackRenderer::SetAlternativeVideoResource_(const boost::any& value) {
- std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, " Alternative video resource [%d]", val);
- if (val == 0) {
- video_decoder_id_ = ResourceCategory::kVideoDecoder;
- video_renderer_id_ = ResourceCategory::kVideoRenderer;
- } else if (val == 1) {
- video_decoder_id_ = ResourceCategory::kVideoDecoderSub;
- video_renderer_id_ = ResourceCategory::kVideoRendererSub;
- } else if (val == 2) {
- video_decoder_id_ = ResourceCategory::kVideoDecoderSub;
- video_renderer_id_ = ResourceCategory::kVideoRenderer;
- } else if (val == 3) {
- video_decoder_id_ = ResourceCategory::kVideoDecoder;
- video_renderer_id_ = ResourceCategory::kVideoRendererSub;
- } else
- return false;
- return true;
-}
-
-bool TrackRenderer::SetVideoDecodingMode_(const boost::any& value) {
- std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, "Video decoding mode [%u]", val);
- video_decoding_mode_ = val;
+ TRACKRENDERER_ERROR(" Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+ fmm_mode_ = (val != 0) ? true : false;
return true;
}
-bool TrackRenderer::SetLateVideoFrameDropMode_(const boost::any& value) {
- std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, " LateVideoFrameDropMode [%s]",
- (val != 0) ? "TRUE" : "FALSE");
- drop_all_late_video_ = (val != 0) ? true : false;
- return true;
-}
-// LCOV_EXCL_STOP
-
void TrackRenderer::GstElementLowLatency_(const TrackType& type) {
- if (low_latency_mode_ ==
- static_cast<std::uint32_t>(LowLatencyMode::kLowLatencyModeNone))
- return;
-
+ if (low_latency_mode_ == 0) return;
switch (type) {
case kTrackTypeAudio:
if (low_latency_mode_ & kLowLatencyModeAudio) {
- constexpr gint kDecodingType = 0x01;
- constexpr gint kDeviceLatency = 0;
- pipeline_->SetProperty(Elements::kDecAudio, "decoding-type",
- kDecodingType);
- pipeline_->SetProperty(Elements::kSinkAudio, "device-latency",
- kDeviceLatency);
+ pipeline_->SetProperty(Elements::kDecAudio, "decoding-type", 0x01);
+ pipeline_->SetProperty(Elements::kSinkAudio, "device-latency", 0);
}
if (low_latency_mode_ & kLowLatencyModeDisableAVSync) {
- constexpr guint64 kLowLatencyMaxBytes = 200;
- constexpr guint64 kFastRendering = 0;
- pipeline_->SetProperty(Elements::kAppSrcAudio, "max-bytes",
- kLowLatencyMaxBytes, "noqueue", TRUE);
pipeline_->SetProperty(Elements::kSinkAudio, "sync", FALSE, "async",
FALSE);
- pipeline_->SetProperty(Elements::kSinkAudio, "fast-rendering",
- kFastRendering);
+ pipeline_->SetProperty(Elements::kSinkAudio, "fast-rendering", 0);
pipeline_->SetProperty(Elements::kSinkAudio, "game-mode", TRUE);
pipeline_->SetProperty(Elements::kSinkAudio, "free-run", TRUE);
}
- if (low_latency_mode_ & kLowLatencyModeDisablePreroll) {
- pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
- }
break;
case kTrackTypeVideo:
if (low_latency_mode_ & kLowLatencyModeVideo) {
- constexpr gint kDecodingType = 0x01;
- pipeline_->SetProperty(Elements::kDecVideo, "decoding-type",
- kDecodingType);
-
- if ((low_latency_mode_ & kLowLatencyModeVideoDistortionConcealment) ==
- kLowLatencyModeVideoDistortionConcealment)
- pipeline_->SetProperty(Elements::kDecVideo, "error-concealment",
- TRUE);
+ pipeline_->SetProperty(Elements::kDecVideo, "decoding-type", 0x01);
}
if (low_latency_mode_ & kLowLatencyModeDisableAVSync) {
pipeline_->SetProperty(Elements::kSinkVideo, "sync", FALSE, "async",
FALSE);
}
- if (low_latency_mode_ & kLowLatencyModeDisableVideoQuality) {
- constexpr uint32_t kDisableVideoQuality = 0x04;
- display_->SetVideoQualityMode(kDisableVideoQuality);
- }
- if (low_latency_mode_ & kLowLatencyModeDisablePreroll) {
- pipeline_->SetProperty(Elements::kSinkVideo, "async", FALSE);
- }
break;
case kTrackTypeSubtitle:
- if (low_latency_mode_ & kLowLatencyModeDisableAVSync) {
- pipeline_->SetProperty(Elements::kSinkCaption, "sync", FALSE, "async",
- FALSE);
- pipeline_->SetProperty(Elements::kSinkSubtitle, "sync", FALSE, "async",
- FALSE);
- }
- if (low_latency_mode_ & kLowLatencyModeDisablePreroll) {
- pipeline_->SetProperty(Elements::kSinkSubtitle, "async", FALSE);
- }
break;
default:
- TRACKRENDERER_ERROR_P(this, "wrong track type");
+ TRACKRENDERER_ERROR("wrong track type");
}
}
-// LCOV_EXCL_START
void TrackRenderer::GetResolutionInfo_(EventMsg* event_msg) {
if (!pipeline_) return;
auto video_sink_caps =
event_msg->data = info;
event_msg->len = event_msg->data.length();
}
-// LCOV_EXCL_STOP
void TrackRenderer::UpdatePlaybackInfo_(bool is_updating) {
if (!pipeline_ || !playback_info_) return;
playback_info_->VconfSetMsgShow();
}
-// LCOV_EXCL_START
GstPadProbeReturn TrackRenderer::GstSrcPadProbeBlockCb_(GstPad* pad,
GstPadProbeInfo* info,
gpointer userdata) {
- TRACKRENDERER_ENTER_P(userdata);
+ TRACKRENDERER_ENTER;
+
+ if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
+ GstEvent* event = GST_PAD_PROBE_INFO_EVENT(info);
+
+ if (!GST_EVENT_IS_SERIALIZED(event)) {
+ TRACKRENDERER_DEBUG("pass non-serialized event");
+ return GST_PAD_PROBE_PASS;
+ }
+
+ if (GST_EVENT_IS_STICKY(event) && GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
+ TRACKRENDERER_DEBUG("pass sticky event");
+ return GST_PAD_PROBE_PASS;
+ }
+ }
+ TRACKRENDERER_LEAVE
return GST_PAD_PROBE_OK;
}
-// LCOV_EXCL_STOP
GstPadProbeReturn TrackRenderer::GstSrcPadProbeIdleCb_(GstPad* pad,
GstPadProbeInfo* info,
gpointer userdata) {
- TRACKRENDERER_ENTER_P(userdata);
+ TRACKRENDERER_ENTER;
auto gstpad = static_cast<Pipeline<Elements>::Pad*>(userdata);
std::unique_lock<std::mutex> pad_block_locker(gstpad->m);
gstpad->is_idle = true;
gstpad->cv.notify_one();
- TRACKRENDERER_LEAVE_P(userdata)
+ TRACKRENDERER_LEAVE
return GST_PAD_PROBE_DROP;
}
-void TrackRenderer::FlushDownStream_(Elements element, const char* key,
- gboolean reset_time) {
- TRACKRENDERER_ENTER_P(this);
+void TrackRenderer::FlushAudioDownStream_(Elements element) {
+ TRACKRENDERER_ENTER;
if (!pipeline_) return;
Pipeline<Elements>::Pad pad;
- pipeline_->PadAddProbe(element, key, "src", GST_PAD_PROBE_TYPE_IDLE,
- GstSrcPadProbeIdleCb_, &pad, nullptr);
+ pipeline_->PadAddProbe(element, kPadProbeAudioIdle, "src",
+ GST_PAD_PROBE_TYPE_IDLE, GstSrcPadProbeIdleCb_, &pad,
+ nullptr);
+
+ pipeline_->FlushDownStream(element);
- if (pipeline_->FlushDownStream(element, reset_time)) {
+ {
std::unique_lock<std::mutex> pad_block_locker(pad.m);
if (!pad.is_idle) {
pad.cv.wait(pad_block_locker);
- TRACKRENDERER_INFO_P(this, "pad block wait end");
+ TRACKRENDERER_INFO("pad block wait end");
}
}
- pipeline_->PadRemoveProbe(key);
- TRACKRENDERER_LEAVE_P(this);
+ pipeline_->PadRemoveProbe(kPadProbeAudioIdle);
+ TRACKRENDERER_LEAVE;
}
-// LCOV_EXCL_START
bool TrackRenderer::ActivateAudio_() {
- TRACKRENDERER_ENTER_P(this)
+ TRACKRENDERER_ENTER
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
if (state_ == State::kStopped) return false;
- if (state_ == State::kResourceConflicted) {
- TRACKRENDERER_WARN_P(this, "Resource conflict!");
- return false;
- }
if (!pipeline_) return false;
- if (is_audioactivated_) {
- TRACKRENDERER_WARN_P(this, "Audio has been activated!");
- return false;
- }
Track track;
if (!track_util::GetActiveTrack(trackinfo_, kTrackTypeAudio, &track)) {
- TRACKRENDERER_ERROR_P(this, "Failed to find active audio track.");
+ TRACKRENDERER_ERROR("Failed to find active audio track.");
return false;
}
-
- if (!GetResource_(kTrackTypeAudio)) {
- TRACKRENDERER_ERROR_P(this,
- "Audio resource allocation fail! ChangeTrack fail.");
- return false;
- }
-
- const char* kDecoderPluginName = nullptr;
- if (internal::IsDecoderElementNecessary(track.mimetype)) {
- kDecoderPluginName = GetDecoderPluginName_(kTrackTypeAudio, track.mimetype);
- if (nullptr == kDecoderPluginName) {
- TRACKRENDERER_ERROR_P(this, "Audio decoder plugin name is nullptr");
- return false;
- } else if (strcmp(kDecoderPluginName, kSkippedResource) == 0) {
- TRACKRENDERER_ERROR_P(this, "The audio resource is NOT_PERMITTED.");
- return false;
- }
- }
-
Elements element = Elements::kAppSrcAudio;
if (internal::IsDrmEmeElementNecessary(drm_property_, track.mimetype)) {
element = Elements::kDrmAudio;
}
-
pipeline_->PadAddProbe(element, kPadProbeAudioBlock, "src",
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
GstSrcPadProbeBlockCb_, nullptr, nullptr);
- pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
- FlushDownStream_(element, kPadProbeAudioIdle, FALSE);
- pipeline_->BinRemove(Elements::kBinAudio, Elements::kSinkAudio);
-
- if (internal::IsDecoderElementNecessary(track.mimetype)) {
- pipeline_->FactoryMake(Elements::kDecAudio, kDecoderPluginName, NULL);
- pipeline_->SetProperty(Elements::kDecAudio, "support-codec-change",
- support_audio_codec_change_);
- if (low_latency_mode_ ==
- static_cast<std::uint32_t>(LowLatencyMode::kLowLatencyModeNone)) {
- constexpr int kPtsManipulationThreshold = 99000; // 99ms
- pipeline_->SetProperty(Elements::kDecAudio, "set-usr-cal-timestamp",
- kPtsManipulationThreshold);
- }
+ pipeline_->SetProperty(Elements::kFakeSinkAudio, "async", FALSE);
+ FlushAudioDownStream_(element);
+ pipeline_->BinRemove(Elements::kBinAudio, Elements::kFakeSinkAudio);
+
+ auto caps = caps_builder_.Build(track, internal::IsDrmEmeElementNecessary(
+ drm_property_, track.mimetype));
+ pipeline_->FactoryMake(Elements::kDecAudio, (GstCaps*)caps.GetCaps_(),
+ GST_ELEMENT_FACTORY_TYPE_DECODER, NULL);
+ pipeline_->FactoryMake(
+ Elements::kSinkAudio,
+ internal::GetAudioSinkPluginName(track.use_swdecoder, track.mimetype),
+ nullptr);
+ if (volume_ != kVolumeNone) {
+ SetVolume_();
}
- std::string audiosink_name =
- GetAudioSinkPluginName_(track.use_swdecoder, track.mimetype);
- CreateAudioSink_(audiosink_name);
- GstElementLowLatency_(kTrackTypeAudio);
+ pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
- gboolean is_async = FALSE;
- pipeline_->GetProperty(Elements::kSinkAudio, "async", &is_async);
- if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
pipeline_->BinAdd(Elements::kBinAudio, Elements::kDecAudio,
- Elements::kAudioConvert, Elements::kCapsFillterDefault,
- Elements::kAudioResample, Elements::kCapsFillter2,
- Elements::kScaleTempo, Elements::kSinkAudio);
- if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", TRUE);
+ Elements::kSinkAudio);
+ pipeline_->SetProperty(Elements::kSinkAudio, "sync", TRUE, "async", TRUE);
+ pipeline_->SetProperty(Elements::kSinkAudio, "multiview-window-id",
+ static_cast<int>(display_->GetSurfaceId()));
pipeline_->PadRemoveProbe(kPadProbeAudioBlock);
- AvocPlayRequest_();
- SetAudioOut_();
-
is_audioactivated_ = true;
- TRACKRENDERER_LEAVE_P(this)
+ TRACKRENDERER_LEAVE
return true;
}
bool TrackRenderer::DeactivateAudio_() {
- TRACKRENDERER_ENTER_P(this)
+ TRACKRENDERER_ENTER
std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
if (state_ == State::kStopped) return false;
- if (state_ == State::kResourceConflicted) {
- TRACKRENDERER_WARN_P(this, "Resource conflict!");
- return false;
- }
if (!pipeline_) return false;
if (!is_audioactivated_) {
- TRACKRENDERER_WARN_P(this, "Audio has been deactivated!");
+ TRACKRENDERER_WARN("Audio has been deactivated!");
return false;
}
-#ifndef SOUNDBAR_PRODUCT
- int result = avoc_player_disconnect(avoc_id_);
- TRACKRENDERER_INFO_P(this, "avoc_player_disconnect() return value[%d]",
- result);
-#endif
-
Track track;
if (!track_util::GetActiveTrack(trackinfo_, kTrackTypeAudio, &track)) {
- TRACKRENDERER_ERROR_P(this, "Failed to find active audio track.");
+ TRACKRENDERER_ERROR("Failed to find active audio track.");
return false;
}
Elements element = Elements::kAppSrcAudio;
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
GstSrcPadProbeBlockCb_, nullptr, nullptr);
pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
- FlushDownStream_(element, kPadProbeAudioIdle, FALSE);
+ FlushAudioDownStream_(element);
pipeline_->BinRemove(Elements::kBinAudio, Elements::kDecAudio,
- Elements::kAudioConvert, Elements::kCapsFillterDefault,
- Elements::kAudioResample, Elements::kCapsFillter2,
- Elements::kScaleTempo, Elements::kSinkAudio);
-
+ Elements::kSinkAudio);
std::string sink_name("fakesink");
if (internal::IsTzMimeType(track.mimetype)) {
sink_name = "tzfakesink";
}
- CreateAudioSink_(sink_name);
- GstElementLowLatency_(kTrackTypeAudio);
- gboolean is_async = FALSE;
- pipeline_->GetProperty(Elements::kSinkAudio, "async", &is_async);
- if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
- pipeline_->BinAdd(Elements::kBinAudio, Elements::kSinkAudio);
- if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", TRUE);
+ pipeline_->FactoryMake(Elements::kFakeSinkAudio, sink_name.c_str(), NULL);
+ pipeline_->SetProperty(Elements::kFakeSinkAudio, "async", TRUE, NULL);
+ pipeline_->SetProperty(Elements::kFakeSinkAudio, "sync", TRUE, NULL);
+ pipeline_->SetProperty(Elements::kFakeSinkAudio, "max-lateness", -1, NULL);
+ pipeline_->SetProperty(Elements::kFakeSinkAudio, "no-drop", TRUE, NULL);
+ pipeline_->BinAdd(Elements::kBinAudio, Elements::kFakeSinkAudio);
pipeline_->PadRemoveProbe(kPadProbeAudioBlock);
- resource_manager_->Dealloc(audio_decoder_id_);
- resource_manager_->Dealloc(audio_out_id_);
is_audioactivated_ = false;
- TRACKRENDERER_LEAVE_P(this)
- return true;
-}
-
-void TrackRenderer::MultiviewStartAudioCb_(int player_id, void* data) {
- TRACKRENDERER_ENTER;
- if (data == nullptr) return;
- auto tr = static_cast<TrackRenderer*>(data);
- TRACKRENDERER_INFO_P(tr, "player_id: %d, avoc id: %d", player_id,
- tr->avoc_id_);
- if (player_id == tr->avoc_id_) {
- tr->is_multiscreen_ = Vconf::Instance().IsMultiscreenMode();
- tr->ActivateAudio_();
- TRACKRENDERER_INFO_P(tr, "Send audio pipeline start done event!");
- rc_player_audio_start_done(player_id);
- }
- TRACKRENDERER_LEAVE_P(tr)
-}
-
-void TrackRenderer::MultiviewStopAudioCb_(int player_id, void* data) {
- TRACKRENDERER_ENTER
- if (data == nullptr) return;
- auto tr = static_cast<TrackRenderer*>(data);
- TRACKRENDERER_INFO_P(tr, "player_id: %d, avoc id: %d", player_id,
- tr->avoc_id_);
- if (player_id == tr->avoc_id_) {
- tr->DeactivateAudio_();
- rc_player_audio_stop_done(player_id);
- TRACKRENDERER_INFO_P(tr, "Send audio pipeline stop done event!");
- }
- TRACKRENDERER_LEAVE_P(tr)
-}
-
-void TrackRenderer::MultiviewResyncAudioCb_(int player_id, void* data) {
- TRACKRENDERER_ENTER
- if (data == nullptr) return;
- auto tr = static_cast<TrackRenderer*>(data);
- TRACKRENDERER_INFO_P(tr, "player_id: %d, avoc id: %d", player_id,
- tr->avoc_id_);
- if (player_id != tr->avoc_id_) return;
- tr->ResyncAudio_();
- TRACKRENDERER_LEAVE_P(tr)
-}
-
-bool TrackRenderer::ResyncAudio_() {
- TRACKRENDERER_ENTER_P(this)
- // internal_audio_m_ is needed to prevent state-change, audio pipeline
- // manipulation, set volume and audio mute in progress of ResyncAudio_()
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
- if (state_ == State::kStopped) return false;
- if (state_ == State::kResourceConflicted) {
- TRACKRENDERER_ERROR_P(this, "Resource conflict!");
- return false;
- }
- if (!pipeline_) return false;
- AvocPlayRequest_();
- resync_audio_policy_->Resync(pipeline_);
-#ifdef SOUNDBAR_PRODUCT
- if (!is_sound_mute_) avoc_av_audio_mute(avoc_id_, AVOC_SETTING_OFF);
-#else
- if (!is_sound_mute_) avoc_audio_mute(avoc_id_, AVOC_SETTING_OFF);
-#endif
- return true;
-} // namespace trackrenderer
-
-void TrackRenderer::MultiviewStartVideoCb_(int player_id, void* data) {
- TRACKRENDERER_ENTER;
- if (data == nullptr) return;
- auto tr = static_cast<TrackRenderer*>(data);
- TRACKRENDERER_INFO_P(tr, "player_id: %d, avoc id: %d", player_id,
- tr->avoc_id_);
- if (player_id != tr->avoc_id_) return;
- BOOST_SCOPE_EXIT(&player_id) { rc_player_video_start_done(player_id); }
- BOOST_SCOPE_EXIT_END
- if (tr->state_ == State::kStopped ||
- tr->state_ == State::kResourceConflicted) {
- TRACKRENDERER_WARN_P(tr, "player state: %d", static_cast<int>(tr->state_));
- return;
- }
- if (!tr->pipeline_ || tr->is_videoactivated_) {
- TRACKRENDERER_WARN_P(tr, "is_videoactivated_: %d", tr->is_videoactivated_);
- return;
- }
- tr->is_multiscreen_ = Vconf::Instance().IsMultiscreenMode();
- tr->eventlistener_->OnMultiviewStartVideo();
- tr->is_videoactivated_ = true;
- TRACKRENDERER_LEAVE_P(tr)
-}
-
-void TrackRenderer::MultiviewStopVideoCb_(int player_id, void* data) {
- TRACKRENDERER_ENTER
- if (data == nullptr) return;
- auto tr = static_cast<TrackRenderer*>(data);
- TRACKRENDERER_INFO_P(tr, "player_id: %d, avoc id: %d", player_id,
- tr->avoc_id_);
- if (player_id != tr->avoc_id_) return;
- BOOST_SCOPE_EXIT(&player_id) { rc_player_video_stop_done(player_id); }
- BOOST_SCOPE_EXIT_END
- if (tr->state_ == State::kStopped ||
- tr->state_ == State::kResourceConflicted) {
- TRACKRENDERER_WARN_P(tr, "player state: %d", static_cast<int>(tr->state_));
- return;
- }
- if (!tr->pipeline_ || !tr->is_videoactivated_) {
- TRACKRENDERER_WARN_P(tr, "is_videoactivated_: %d", tr->is_videoactivated_);
- return;
- }
- tr->eventlistener_->OnMultiviewStopVideo();
- tr->is_videoactivated_ = false;
- TRACKRENDERER_LEAVE_P(tr)
-}
-// LCOV_EXCL_STOP
-
-void TrackRenderer::SetVconfCb_() {
- TRACKRENDERER_ENTER_P(this)
- std::vector<std::string> names;
- names.push_back(kPowerAnimationVconf);
-
- Vconf::Instance().SetVconfsCb(names, TrackRenderer::VconfCb_, this);
- is_multiscreen_ = Vconf::Instance().IsMultiscreenMode();
- TRACKRENDERER_LEAVE_P(this)
-}
-
-void TrackRenderer::UnsetVconfCb_() {
- TRACKRENDERER_ENTER_P(this)
- std::vector<std::string> names;
- names.push_back(kPowerAnimationVconf);
-
- Vconf::Instance().UnsetVconfsCb(names, TrackRenderer::VconfCb_, this);
- TRACKRENDERER_LEAVE_P(this)
-}
-
-// LCOV_EXCL_START
-void TrackRenderer::VconfCb_(const std::string& name, const std::string& value,
- void* userdata) {
- TRACKRENDERER_ENTER
- if (userdata == nullptr) return;
- auto tr = static_cast<TrackRenderer*>(userdata);
- if (name == kPowerAnimationVconf) {
- std::lock_guard<std::mutex> lk(tr->resource_m_);
- if (tr->state_ == State::kStopped) return;
- if (tr->state_ == State::kResourceConflicted) {
- TRACKRENDERER_WARN_P(tr, "Resource conflict!");
- return;
- }
- if (!tr->pipeline_) return;
- gboolean is_mute = (value == "true") ? TRUE : FALSE;
- tr->pipeline_->SetProperty(Elements::kSinkAudio, "mute", is_mute);
- TRACKRENDERER_WARN_P(tr, "[%s] audio!", is_mute ? "Mute" : "Unmute");
- } else {
- TRACKRENDERER_ERROR_P(tr, "Unknow vconf name: %s", name.c_str());
- }
-
- TRACKRENDERER_LEAVE_P(tr)
-}
-// LCOV_EXCL_STOP
-
-bool TrackRenderer::SetResourceCenterCallback_() {
- TRACKRENDERER_ENTER_P(this)
-
- audio_start_cb_id_ = rc_register_player_audio_start_request_callback(
- MultiviewStartAudioCb_, this);
- audio_stop_cb_id_ = rc_register_player_audio_stop_request_callback(
- MultiviewStopAudioCb_, this);
- audio_resync_cb_id_ = rc_register_player_audio_resync_request_callback(
- MultiviewResyncAudioCb_, this);
-
- video_start_cb_id_ = rc_register_player_video_start_request_callback(
- MultiviewStartVideoCb_, this);
- video_stop_cb_id_ = rc_register_player_video_stop_request_callback(
- MultiviewStopVideoCb_, this);
-
- bool ret = true;
- if (audio_start_cb_id_ == 0 || audio_stop_cb_id_ == 0 ||
- audio_resync_cb_id_ == 0) {
- TRACKRENDERER_ERROR_P(
- this, "register audio request callback failed: %d, %d, %d",
- audio_start_cb_id_, audio_stop_cb_id_, audio_resync_cb_id_);
- ret = false;
- }
- if (video_start_cb_id_ == 0 || video_stop_cb_id_ == 0) {
- TRACKRENDERER_ERROR_P(this,
- "register video request callback failed: %d, %d",
- video_start_cb_id_, video_stop_cb_id_);
- ret = false;
- }
- TRACKRENDERER_LEAVE_P(this)
- return ret;
-}
-
-bool TrackRenderer::UnsetResourceCenterCallback_() {
- TRACKRENDERER_ENTER_P(this)
-
- auto audio_start_cb_ret =
- rc_unregister_player_audio_start_request_callback(audio_start_cb_id_);
- auto audio_stop_cb_ret =
- rc_unregister_player_audio_stop_request_callback(audio_stop_cb_id_);
- auto audio_resync_cb_ret =
- rc_unregister_player_audio_resync_request_callback(audio_resync_cb_id_);
-
- auto video_start_cb_ret =
- rc_unregister_player_video_start_request_callback(video_start_cb_id_);
- auto video_stop_cb_ret =
- rc_unregister_player_video_stop_request_callback(video_stop_cb_id_);
-
- bool ret = true;
- if (audio_start_cb_ret != 0 || audio_stop_cb_ret != 0 ||
- audio_resync_cb_ret != 0) {
- TRACKRENDERER_ERROR_P(
- this, "unregister audio request callback failed: %d, %d, %d",
- audio_start_cb_ret, audio_stop_cb_ret, audio_resync_cb_ret);
- ret = false;
- }
- if (video_start_cb_ret != 0 || video_stop_cb_ret != 0) {
- TRACKRENDERER_ERROR_P(this,
- "unregister video request callback failed: %d, %d",
- video_start_cb_ret, video_stop_cb_ret);
- ret = false;
- }
- return ret;
- TRACKRENDERER_LEAVE_P(this)
-}
-
-// LCOV_EXCL_START
-void TrackRenderer::SetAlternativeAudioResource(const boost::any& value) {
- std::uint32_t val = boost::any_cast<std::uint32_t>(value);
- TRACKRENDERER_ERROR_P(this, " Alternative audio resource [%s]",
- (val != 0) ? "TRUE" : "FALSE");
- if (val != 0) {
- audio_decoder_id_ = ResourceCategory::kAudioDecoderSub;
- audio_out_id_ = ResourceCategory::kAudioRendererSub;
- } else {
- audio_decoder_id_ = ResourceCategory::kAudioDecoder;
- audio_out_id_ = ResourceCategory::kAudioRenderer;
- }
-}
-// LCOV_EXCL_STOP
-
-bool TrackRenderer::InitAudioEasingInfo(const uint32_t& init_volume,
- const uint32_t& init_elapsed_time,
- const AudioEasingInfo& info) {
- TRACKRENDERER_ENTER_P(this)
- std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
- if (audio_easing_controller_) {
- TRACKRENDERER_ERROR_P(this,
- "audio easing controller is already Initialized");
- return false;
- }
-
- if (init_volume > kVolumeMax || info.target_volume > kVolumeMax) {
- TRACKRENDERER_ERROR_P(this, "volume: %d", info.target_volume);
- return false;
- }
- audio_easing_controller_.reset(
- new AudioEasingController(init_volume, init_elapsed_time, info));
-
- if (info.duration == 0)
- volume_ = audio_easing_controller_->GetGainFromVolume(info.target_volume);
- else
- volume_ = audio_easing_controller_->GetGainFromVolume(init_volume);
- if (pipeline_) SetVolume_();
-
- TRACKRENDERER_LEAVE_P(this)
- return true;
-}
-
-bool TrackRenderer::UpdateAudioEasingInfo(const AudioEasingInfo& info) {
- TRACKRENDERER_ENTER_P(this)
- std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
- if (!audio_easing_controller_) {
- TRACKRENDERER_ERROR_P(this, "audio easing controller is not exist");
- return false;
- }
- if (info.target_volume > kVolumeMax) {
- TRACKRENDERER_ERROR_P(this, "volume: %d", info.target_volume);
- return false;
- }
- auto ret = audio_easing_controller_->SetInfo(info);
- if (!ret) return false;
-
- if (info.duration == 0) {
- volume_ = audio_easing_controller_->GetGainFromVolume(info.target_volume);
- if (pipeline_) SetVolume_();
- }
- TRACKRENDERER_LEAVE_P(this)
- return true;
-}
-
-bool TrackRenderer::GetAudioEasingInfo(uint32_t* current_volume,
- uint32_t* elapsed_time,
- AudioEasingInfo* info) {
- TRACKRENDERER_ENTER_P(this)
- std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
- if (!audio_easing_controller_) {
- TRACKRENDERER_ERROR_P(this, "audio easing controller is not exist");
- return false;
- }
- auto ret =
- audio_easing_controller_->GetInfo(current_volume, elapsed_time, info);
- TRACKRENDERER_LEAVE_P(this)
- return ret;
-}
-
-bool TrackRenderer::StartAudioEasing() {
- TRACKRENDERER_ENTER_P(this)
- std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
- if (!audio_easing_controller_) {
- TRACKRENDERER_ERROR_P(this, "audio easing controller is not exist");
- return false;
- }
- if (state_ == State::kStopped) return false;
- if (!pipeline_) return false;
-
- pipeline_->Execute(Elements::kSinkAudio, [this](GstElement * obj) noexcept {
- return audio_easing_controller_->AudioEasingStart(obj);
- });
+ TRACKRENDERER_LEAVE
return true;
}
-bool TrackRenderer::StopAudioEasing() {
- TRACKRENDERER_ENTER_P(this)
- std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
- return StopAudioEasing_();
-}
-
-bool TrackRenderer::StopAudioEasing_() {
- TRACKRENDERER_ENTER_P(this)
- if (!audio_easing_controller_) {
- TRACKRENDERER_ERROR_P(this, "audio easing controller is not exist");
- return false;
- }
- audio_easing_controller_->AudioEasingStop();
- return true;
-}
-
-bool TrackRenderer::GetVirtualRscId(const RscType type, int* virtual_id) {
- if (virtual_id == nullptr) return false;
- if (type != RscType::kVideoRenderer || virtual_scaler_id_ == -1) {
- *virtual_id = -1;
- return false;
- }
- *virtual_id = virtual_scaler_id_;
- return true;
-}
-
-// LCOV_EXCL_START
-bool TrackRenderer::NeedSyncPause_() {
- if (!support_videodec_underflow_pause_) {
- return false;
- }
- TRACKRENDERER_WARN_P(this, "sync pause");
- pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
- pipeline_->PadAddProbe(Elements::kDecVideo, kPadProbeVideoDecInputBlock,
- "sink", GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
- GstPadProbeVideoDecInputCb_, this, nullptr);
-
- gboolean is_async_video = FALSE, is_async_audio = FALSE;
- pipeline_->GetProperty(Elements::kSinkVideo, "async", &is_async_video);
- if (is_async_video)
- pipeline_->SetProperty(Elements::kSinkVideo, "async", FALSE);
- pipeline_->GetProperty(Elements::kSinkAudio, "async", &is_async_audio);
- if (is_async_audio)
- pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
- pipeline_->SetState(Elements::kPipeline, GST_STATE_PAUSED);
- if (is_async_video)
- pipeline_->SetProperty(Elements::kSinkVideo, "async", TRUE);
- if (is_async_audio)
- pipeline_->SetProperty(Elements::kSinkAudio, "async", TRUE);
- return true;
-}
-// LCOV_EXCL_STOP
-
-void TrackRenderer::SetAudioOut_() {
- TRACKRENDERER_ENTER_P(this)
- if (!pipeline_) return;
-
- /* need to call this api after avoc_play_request_m() */
- rc_player_audio_out_e audio_out;
- rc_get_player_audio_out(avoc_id_, &audio_out);
- TRACKRENDERER_INFO_P(this, "avoc_id_ : %d , rc_audio_out [%d]", avoc_id_,
- audio_out);
-
- int is_audio_sub_out_path = (audio_out == RC_PLAYER_AUDIO_OUT_SUB) ? 1 : 0;
- pipeline_->SetProperty(Elements::kSinkAudio, "device-audio-out",
- is_audio_sub_out_path, NULL);
- pipeline_->SetProperty(Elements::kSinkAudio, "mute", is_sound_mute_, NULL);
- if (volume_ != kVolumeNone) {
- SetVolume_();
- }
- return;
-}
-bool TrackRenderer::SetAdvancedPictureQualityType(
- const AdvPictureQualityType type) {
- TRACKRENDERER_ENTER_P(this)
-#ifndef SOUNDBAR_PRODUCT
- switch (type) {
- case AdvPictureQualityType::kVideoCall:
- avoc_sub_source_ = AVOC_SUB_SOURCE_UNIPLAYER_VIDEOCALL;
- break;
- case AdvPictureQualityType::kUsbCamera:
- avoc_sub_source_ = AVOC_SUB_SOURCE_UNIPLAYER_CAMERA;
- break;
- default:
- return false;
- }
-#endif
- return true;
-}
-
-bool TrackRenderer::SetResourceAllocatePolicy(const RscAllocPolicy policy) {
- TRACKRENDERER_ENTER_P(this)
- rsc_alloc_policy_ = policy;
- return true;
-}
-
-void TrackRenderer::UpdateTrackFrameRate_(const int& framerate_num,
- const int& framerate_den) {
- std::lock_guard<std::mutex> lk(decoded_drop_ctx_.drop_mutex);
- decoded_drop_ctx_.track_fps.num = framerate_num;
- decoded_drop_ctx_.track_fps.den = framerate_den;
- decoded_drop_ctx_.fps_changed = true;
-}
-
-void TrackRenderer::UpdateDecodedDropContext_() {
- std::lock_guard<std::mutex> lk(decoded_drop_ctx_.drop_mutex);
-
- BOOST_SCOPE_EXIT(&decoded_drop_ctx_) {
- decoded_drop_ctx_.fps_changed = false;
- }
- BOOST_SCOPE_EXIT_END
-
- if (decoded_drop_ctx_.fps_changed) {
- Rational track_framerate = decoded_drop_ctx_.track_fps;
- Rational request_framerate = decoded_drop_ctx_.request_fps;
- if (!track_framerate.num || !track_framerate.den ||
- !request_framerate.den) {
- TRACKRENDERER_ERROR("invalid track or request frame rate: %d/%d",
- track_framerate.num, track_framerate.den);
- return;
- }
- if (!request_framerate.num) {
- decoded_drop_ctx_.drop_mode = DropMode::kDropModeAccordingToRate;
- decoded_drop_ctx_.drop_rate = 1;
- decoded_drop_ctx_.base_num = 0;
- return;
- }
- const int64_t tmp1 = track_framerate.num * (int64_t)request_framerate.den;
- const int64_t tmp2 =
- tmp1 - request_framerate.num * (int64_t)track_framerate.den;
- if (tmp2 < 0) {
- TRACKRENDERER_ERROR(
- "request frame rate(%d/%d) can not be larger than track frame "
- "rate(%d/%d)",
- request_framerate.num, request_framerate.den, track_framerate.num,
- track_framerate.den);
- return;
- } else if (!tmp2) {
- decoded_drop_ctx_.drop_mode = DropMode::kDropModeNone;
- } else {
- if (tmp1 % tmp2 == 0) {
- decoded_drop_ctx_.drop_mode = DropMode::kDropModeAccordingToRate;
- decoded_drop_ctx_.drop_rate = static_cast<uint32_t>(tmp1 / tmp2);
- decoded_drop_ctx_.base_num = 0;
- } else if (track_framerate.num == 24 * track_framerate.den &&
- request_framerate.num == 15 * request_framerate.den) {
- decoded_drop_ctx_.drop_mode = DropMode::kDropModeAccordingToTable;
- decoded_drop_ctx_.base_num = 0;
- } else {
- TRACKRENDERER_ERROR(
- "not support case: request frame rate(%d/%d) track frame "
- "rate(%d/%d)",
- request_framerate.num, request_framerate.den, track_framerate.num,
- track_framerate.den);
- return;
- }
- }
- }
- return;
-}
-
-bool TrackRenderer::NeedDropThisDecodedVideoBuffer_() {
- bool ret = false;
-
- UpdateDecodedDropContext_();
- if (decoded_drop_ctx_.drop_mode == DropMode::kDropModeAccordingToRate &&
- decoded_drop_ctx_.drop_rate) {
- uint32_t drop_rate = decoded_drop_ctx_.drop_rate;
- constexpr uint32_t kDropAll = 1;
- decoded_drop_ctx_.base_num++;
- if (drop_rate == kDropAll ||
- (decoded_drop_ctx_.base_num % drop_rate == 0)) {
- decoded_drop_ctx_.base_num = 0;
- ret = true;
- }
- } else if (decoded_drop_ctx_.drop_mode ==
- DropMode::kDropModeAccordingToTable) {
- constexpr uint32_t kDropTable[8] = {0, 0, 1, 0, 0, 1, 0, 1};
-
- decoded_drop_ctx_.base_num = decoded_drop_ctx_.base_num & 0x7;
- if (kDropTable[decoded_drop_ctx_.base_num]) {
- ret = true;
- }
- decoded_drop_ctx_.base_num++;
- }
- return ret;
-}
-
-bool TrackRenderer::SetVideoRendererType(
- const ResourceCategory video_renderer_type) {
- if (video_renderer_type < ResourceCategory::kVideoRenderer) return false;
- if (video_renderer_type > ResourceCategory::kVideoRendererSub3) return false;
- video_renderer_id_ = video_renderer_type;
- return true;
-}
-
-void TrackRenderer::SetVideoParDar(uint64_t time_millisecond, uint32_t par_num,
- uint32_t par_den, uint32_t dar_num,
- uint32_t dar_den) {
- TRACKRENDERER_ENTER_P(this);
- std::lock_guard<std::mutex> lk(resource_m_);
- std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
- if (state_ == State::kStopped) return;
- if (state_ == State::kResourceConflicted) return;
-
- if (!pipeline_) {
- par_dar_.time_millisecond = time_millisecond;
- par_dar_.par_num = par_num;
- par_dar_.par_den = par_den;
- par_dar_.dar_num = dar_num;
- par_dar_.dar_den = dar_den;
- is_pardar_updated_ = true;
- } else {
- pipeline_->SetParDar(Elements::kDecVideo, time_millisecond, par_num,
- par_den, dar_num, dar_den);
- }
- TRACKRENDERER_LEAVE_P(this);
-}
-
} // namespace trackrenderer
} // namespace plusplayer
//
#include "trackrenderer/trackrenderer.h"
-#include "trackrenderer/core/elements.h"
#define MAKE_ATTRIBUTE(attr, elem, type, name, init, value) \
{ \
trackrenderer::Attribute::attr, { \
- trackrenderer::Elements::elem, typeid(type), name, init, value, \
- &::OnAttributeSetWithCasting<type>, \
+ trackrenderer::TrackRenderer::Elements::elem, typeid(type), name, init, \
+ value, &::OnAttributeSetWithCasting<type>, \
&::OnAttributeGetWithCasting<type> \
} \
}
constexpr std::uint64_t kCurrentLevelTimeOfAudio = 0; // 0ns
constexpr std::uint32_t kMinTimeThresholdOfVideo = 0; // 0%
constexpr std::uint32_t kMinTimeThresholdOfAudio = 0; // 0%
-constexpr std::int32_t kInvalidExternalDrmHandle = -1;
-constexpr std::int32_t kIsSupportRotate = 0;
-constexpr std::int64_t kDefaultRenderTimeOffset = 0;
+constexpr std::uint64_t kMaxBufferOfVideoSrcQueue = 5; // cnt
+constexpr std::uint64_t kMaxBufferOfAudioSrcQueue = 5; // cnt
template <typename ValueType>
bool IsSameValue(const boost::any& v1, const boost::any& v2) {
PROPERTY("min-percent"), //
WITHOUT_INIT, //
DEFAULT_VALUE(::kMinByteThresholdOfAudio)), //
- MAKE_ATTRIBUTE(kVideoQueueMaxTime, //
+ MAKE_ATTRIBUTE(kVideoQueueMaxBuffer, //
ELEMENT(kAppSrcVideo), //
VALUE_TYPE(std::uint64_t), //
- PROPERTY("max-time"), //
- WITHOUT_INIT, //
- DEFAULT_VALUE(::kMaxTimeOfVideoSrcQueue)), //
- MAKE_ATTRIBUTE(kAudioQueueMaxTime, //
- ELEMENT(kAppSrcAudio), //
- VALUE_TYPE(std::uint64_t), //
- PROPERTY("max-time"), //
- WITHOUT_INIT, //
- DEFAULT_VALUE(::kMaxTimeOfAudioSrcQueue)), //
- MAKE_ATTRIBUTE(kVideoQueueCurrentLevelTime, //
- ELEMENT(kAppSrcVideo), //
- VALUE_TYPE(std::uint64_t), //
- PROPERTY("current-level-time"), //
- WITHOUT_INIT, //
- DEFAULT_VALUE(::kCurrentLevelTimeOfVideo)), //
- MAKE_ATTRIBUTE(kAudioQueueCurrentLevelTime, //
+ PROPERTY("max-buffers"), //
+ WITH_INIT, //
+ DEFAULT_VALUE(::kMaxBufferOfVideoSrcQueue)), //
+ MAKE_ATTRIBUTE(kAudioQueueMaxBuffer, //
ELEMENT(kAppSrcAudio), //
VALUE_TYPE(std::uint64_t), //
- PROPERTY("current-level-time"), //
- WITHOUT_INIT, //
- DEFAULT_VALUE(::kCurrentLevelTimeOfAudio)), //
- MAKE_ATTRIBUTE(kVideoMinTimeThreshold, //
- ELEMENT(kAppSrcVideo), //
- VALUE_TYPE(std::uint32_t), //
- PROPERTY("min-time-percent"), //
- WITHOUT_INIT, //
- DEFAULT_VALUE(::kMinTimeThresholdOfVideo)), //
- MAKE_ATTRIBUTE(kAudioMinTimeThreshold, //
- ELEMENT(kAppSrcAudio), //
- VALUE_TYPE(std::uint32_t), //
- PROPERTY("min-time-percent"), //
- WITHOUT_INIT, //
- DEFAULT_VALUE(::kMinTimeThresholdOfAudio)), //
- MAKE_ATTRIBUTE(kVideoSupportRotation, //
- ELEMENT(kSinkVideo), //
- VALUE_TYPE(std::uint32_t), //
- PROPERTY("support-rotation"), //
- WITHOUT_INIT, //
- DEFAULT_VALUE(::kIsSupportRotate)), //
- MAKE_ATTRIBUTE(kVideoRenderTimeOffset, //
- ELEMENT(kSinkVideo), //
- VALUE_TYPE(std::int64_t), //
- PROPERTY("ts-offset"), //
- WITHOUT_INIT, //
- DEFAULT_VALUE(::kDefaultRenderTimeOffset)), //
- MAKE_ATTRIBUTE(kAudioRenderTimeOffset, //
- ELEMENT(kSinkAudio), //
- VALUE_TYPE(std::int64_t), //
- PROPERTY("ts-offset"), //
- WITHOUT_INIT, //
- DEFAULT_VALUE(::kDefaultRenderTimeOffset)), //
+ PROPERTY("max-buffers"), //
+ WITH_INIT, //
+ DEFAULT_VALUE(::kMaxBufferOfAudioSrcQueue)), //
};
const TrackRenderer::AttributesByElement TrackRenderer::kAttributesByElem_ =
} // namespace trackrenderer
-} // namespace plusplayer
\ No newline at end of file
+} // namespace plusplayer
#include "trackrenderer_capi/trackrenderer_capi.h"
+#include "trackrenderer_capi/trackrenderer_internal.h"
#include <cassert>
#include <cstdarg>
#include "trackrenderer/trackrenderer.h"
#include "trackrenderer/trackrenderer_capi_utils.h"
#include "trackrenderer/version.h"
-#include "trackrenderer_capi/trackrenderer_internal.h"
//#define DUMP_SUBTITLE_PICTURE
#ifdef DUMP_SUBTITLE_PICTURE
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
+#include <errno.h>
#pragma pack(1)
typedef struct tagBITMAPFILEHEADER {
file_index);
/*Check the soft symbol, refer to
- * */
+ * http://wiki.vd.sec.samsung.net/display/prodSecuGuide/H6.1%20fopen,%20open,%20freopen,%20std_ofstream*/
/*File information is obtained by using lstat function.*/
if (lstat(path, &ls) == -1) {
if (errno != ENOENT) {
bFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
(4 * (width * height));
outARGBadd_bmp = (unsigned char*)malloc(width * height * 4);
- if (!outARGBadd_bmp) return -1;
for (height_count = 0; height_count < height; ++height_count) {
memcpy(outARGBadd_bmp + (height - height_count - 1) * width * 4,
outARGBadd + height_count * width * 4, width * 4);
explicit TrackRendererEventListener(TrackRendererPriv* handler)
: handler_(handler) {}
void OnError(const plusplayer::trackrenderer::ErrorType& error_code) override;
- void OnErrorMsg(const plusplayer::trackrenderer::ErrorType& error_code,
- char* error_msg) override;
void OnResourceConflicted() override;
void OnSeekDone() override;
void OnFlushDone() override;
void OnEos() override;
void OnEvent(const plusplayer::trackrenderer::EventType& event,
const plusplayer::trackrenderer::EventMsg& msg_data) override;
- void OnFirstDecodingDone() override;
void OnSubtitleData(
const plusplayer::trackrenderer::DecoderInputBufferPtr& buf,
const plusplayer::trackrenderer::SubtitleType& type) override;
const plusplayer::trackrenderer::BufferStatus& status) override;
void OnSeekData(const plusplayer::trackrenderer::TrackType& type,
const uint64_t offset) override;
- void OnMediaPacketGetTbmBufPtr(void** ptr, bool is_scale_change) override;
void OnMediaPacketVideoDecoded(
const plusplayer::trackrenderer::DecodedVideoPacket& packet) override;
- void OnMediaRawPacketVideoDecoded(
- plusplayer::trackrenderer::DecodedVideoRawModePacket& packet) override;
- void OnVideoDecoderUnderrun() override;
- void OnVideoLatencyStatus(
- const plusplayer::trackrenderer::LatencyStatus& latency_status) override;
- void OnAudioLatencyStatus(
- const plusplayer::trackrenderer::LatencyStatus& latency_status) override;
- void OnVideoHighLatency() override;
- void OnAudioHighLatency() override;
- void OnMultiviewStartVideo() override;
- void OnMultiviewStopVideo() override;
private:
TrackRendererPriv* handler_ = nullptr;
trackrenderer_error_cb error_cb = nullptr;
void* error_cb_userdata = nullptr;
- trackrenderer_error_msg_cb error_msg_cb = nullptr;
- void* error_msg_cb_userdata = nullptr;
-
trackrenderer_resource_conflicted_cb resourceconflict_cb = nullptr;
void* resourceconflict_cb_userdata = nullptr;
trackrenderer_event_cb event_cb = nullptr;
void* event_cb_userdata = nullptr;
- trackrenderer_first_decoding_done_cb first_decoding_done_cb = nullptr;
- void* first_decoding_done_cb_userdata = nullptr;
-
trackrenderer_subtitle_rawdata_cb subtitle_rawdata_cb = nullptr;
void* subtitle_rawdata_cb_userdata = nullptr;
trackrenderer_seekdata_cb seekdata_cb = nullptr;
void* seekdata_cb_userdata = nullptr;
- trackrenderer_media_packet_video_tbmptr_cb video_tbmptr_cb = nullptr;
- void* video_tbmptr_cb_userdata = nullptr;
-
trackrenderer_media_packet_video_decoded_cb video_decoded_cb = nullptr;
void* video_decoded_cb_userdata = nullptr;
-
- trackrenderer_media_packet_video_raw_decoded_cb video_raw_decoded_cb =
- nullptr;
- void* video_raw_decoded_cb_userdata = nullptr;
-
- trackrenderer_decoder_underrun_cb video_decoder_underrun_cb = nullptr;
- void* video_decoder_underrun_cb_userdata = nullptr;
-
- trackrenderer_video_latency_status_cb video_latency_status_cb = nullptr;
- trackrenderer_audio_latency_status_cb audio_latency_status_cb = nullptr;
- void* video_latency_status_cb_userdata = nullptr;
- void* audio_latency_status_cb_userdata = nullptr;
- trackrenderer_video_high_latency_cb video_high_latency_cb = nullptr;
- trackrenderer_audio_high_latency_cb audio_high_latency_cb = nullptr;
- void* video_high_latency_cb_userdata = nullptr;
- void* audio_high_latency_cb_userdata = nullptr;
-
- trackrenderer_multiview_start_video_cb multiview_start_video_cb = nullptr;
- trackrenderer_multiview_stop_video_cb multiview_stop_video_cb = nullptr;
- void* multiview_start_video_cb_userdata = nullptr;
- void* multiview_stop_video_cb_userdata = nullptr;
-
std::unique_ptr<TrackRendererEventListener> eventlistener{
new TrackRendererEventListener(this)};
handler_->error_cb_userdata);
}
-void TrackRendererEventListener::OnErrorMsg(
- const plusplayer::trackrenderer::ErrorType& error_code, char* error_msg) {
- if (handler_->error_msg_cb == nullptr) return;
- handler_->error_msg_cb(
- plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererErrorType(
- error_code),
- error_msg, handler_->error_cb_userdata);
-}
-
void TrackRendererEventListener::OnResourceConflicted() {
if (handler_->resourceconflict_cb == nullptr) return;
handler_->resourceconflict_cb(handler_->resourceconflict_cb_userdata);
event_msg, handler_->event_cb_userdata);
}
-void TrackRendererEventListener::OnFirstDecodingDone() {
- if (handler_->first_decoding_done_cb == nullptr) return;
- handler_->first_decoding_done_cb(handler_->first_decoding_done_cb_userdata);
-}
-
void TrackRendererEventListener::OnSubtitleData(
const plusplayer::trackrenderer::DecoderInputBufferPtr& buf,
const plusplayer::trackrenderer::SubtitleType& type) {
offset, handler_->seekdata_cb_userdata);
}
-void TrackRendererEventListener::OnMediaPacketGetTbmBufPtr(
- void** ptr, bool is_scale_change) {
- if (handler_->video_tbmptr_cb == nullptr) return;
- handler_->video_tbmptr_cb(ptr, is_scale_change,
- handler_->video_tbmptr_cb_userdata);
-}
-
void TrackRendererEventListener::OnMediaPacketVideoDecoded(
const plusplayer::trackrenderer::DecodedVideoPacket& packet) {
if (handler_->video_decoded_cb == nullptr) return;
handler_->video_decoded_cb(&_packet, handler_->video_decoded_cb_userdata);
}
-void TrackRendererEventListener::OnMediaRawPacketVideoDecoded(
- plusplayer::trackrenderer::DecodedVideoRawModePacket& packet) {
- if (handler_->video_raw_decoded_cb == nullptr) return;
- TrackRendererDecodedVideoRawModePacket _packet;
- _packet.pts = packet.pts;
- _packet.width = packet.width;
- _packet.height = packet.height;
- _packet.internal_data = static_cast<void*>(&packet.data);
- handler_->video_raw_decoded_cb(
- &_packet, static_cast<TrackRendererDecodedVideoType>(packet.type),
- handler_->video_raw_decoded_cb_userdata);
-}
-
-void TrackRendererEventListener::OnVideoDecoderUnderrun() {
- if (handler_->video_decoder_underrun_cb == nullptr) return;
- handler_->video_decoder_underrun_cb(
- handler_->video_decoder_underrun_cb_userdata);
-}
-
-void TrackRendererEventListener::OnVideoLatencyStatus(
- const plusplayer::trackrenderer::LatencyStatus& latency_status) {
- if (handler_->video_latency_status_cb == nullptr) return;
- handler_->video_latency_status_cb(
- plusplayer::trackrenderer::capi_utils::
- ConvertToTrackrendererLatencyStatus(latency_status),
- handler_->video_latency_status_cb_userdata);
-}
-
-void TrackRendererEventListener::OnAudioLatencyStatus(
- const plusplayer::trackrenderer::LatencyStatus& latency_status) {
- if (handler_->audio_latency_status_cb == nullptr) return;
- handler_->audio_latency_status_cb(
- plusplayer::trackrenderer::capi_utils::
- ConvertToTrackrendererLatencyStatus(latency_status),
- handler_->audio_latency_status_cb_userdata);
-}
-
-void TrackRendererEventListener::OnVideoHighLatency() {
- if (handler_->video_high_latency_cb == nullptr) return;
- handler_->video_high_latency_cb(handler_->video_high_latency_cb_userdata);
-}
-
-void TrackRendererEventListener::OnAudioHighLatency() {
- if (handler_->audio_high_latency_cb == nullptr) return;
- handler_->audio_high_latency_cb(handler_->audio_high_latency_cb_userdata);
-}
-
-void TrackRendererEventListener::OnMultiviewStartVideo() {
- if (handler_->multiview_start_video_cb == nullptr) return;
- handler_->multiview_start_video_cb(
- handler_->multiview_start_video_cb_userdata);
-}
-
-void TrackRendererEventListener::OnMultiviewStopVideo() {
- if (handler_->multiview_stop_video_cb == nullptr) return;
- handler_->multiview_stop_video_cb(handler_->multiview_stop_video_cb_userdata);
-}
-
using TrackRendererPrivPtr = TrackRendererPriv::Ptr;
TrackRendererPrivPtr Create() {
return kSuccess;
}
-int trackrenderer_set_track_handle(
- TrackRendererHandle handle, const TrackRendererTrackHandle* handles_array,
- const int array_size) {
- if (array_size <= 0 || array_size > kTrackRendererMaxStreamNumber)
- return kFailed;
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- auto trackinfo =
- plusplayer::trackrenderer::capi_utils::MakeTrackFromTrackHandle(
- handles_array, array_size);
- return priv->renderer->SetTrack(trackinfo) ? kSuccess : kFailed;
-}
-
void trackrenderer_set_ini_property(TrackRendererHandle handle,
TrackRendererIniProperty* properties,
int property_size) {
priv->renderer->SetIniProperty(iniproperty);
}
+void trackrenderer_set_ini_element(TrackRendererHandle handle,
+ TrackRendererIniElement* elements,
+ int element_size) {
+ auto priv = static_cast<TrackRendererPrivPtr>(handle);
+ if (!priv) return;
+ std::map<std::string, std::string> inielement =
+ plusplayer::trackrenderer::capi_utils::MakeIniElement(elements,
+ element_size);
+ priv->renderer->SetIniElement(inielement);
+}
+
int trackrenderer_seek(TrackRendererHandle handle,
unsigned long long time_millisecond,
double playback_rate) {
}
int trackrenderer_get_playing_time(TrackRendererHandle handle,
- unsigned long long* time_millisecond) {
+ uint64_t* time_millisecond) {
auto priv = static_cast<TrackRendererPrivPtr>(handle);
if (!priv) return kFailed;
if (priv->renderer->GetPlayingTime(time_millisecond) == false) {
return kSuccess;
}
-int trackrenderer_get_dropped_frames_for_catchup(TrackRendererHandle handle,
- TrackRendererTrackType type,
- void* counts) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- if (priv->renderer->GetDroppedFramesForCatchup(
- plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type),
- counts) == false) {
- return kFailed;
- }
- return kSuccess;
-}
-
int trackrenderer_deactivate(TrackRendererHandle handle,
TrackRendererTrackType type) {
auto priv = static_cast<TrackRendererPrivPtr>(handle);
#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
auto inputbuffer = plusplayer::trackrenderer::DecoderInputBuffer::Create(
plusplayer::trackrenderer::capi_utils::ConvertToTrackType(data->type),
- data->index, static_cast<GstBuffer*>(data->buffer));
+ data->index, static_cast<GstBuffer*>(data->buffer), static_cast<GstCaps*>(data->caps));
#else
auto inputbuffer = plusplayer::trackrenderer::DecoderInputBuffer::Create(
plusplayer::trackrenderer::capi_utils::ConvertToTrackType(data->type),
- data->index, data->buffer);
+ data->index, data->buffer, data->caps);
#endif
SubmitStatus status;
#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
auto inputbuffer = plusplayer::trackrenderer::DecoderInputBuffer::Create(
plusplayer::trackrenderer::capi_utils::ConvertToTrackType(data->type),
- data->index, static_cast<GstBuffer*>(data->buffer), false);
+ data->index, static_cast<GstBuffer*>(data->buffer), static_cast<GstCaps*>(data->caps), false);
#else
auto inputbuffer = plusplayer::trackrenderer::DecoderInputBuffer::Create(
plusplayer::trackrenderer::capi_utils::ConvertToTrackType(data->type),
- data->index, data->buffer, false);
+ data->index, data->buffer, data->caps, false);
#endif
SubmitStatus status;
plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type));
}
+void trackrenderer_set_drm_license_key(TrackRendererHandle handle,
+ TrackRendererTrackType type,
+ const char* key) {
+ auto priv = static_cast<TrackRendererPrivPtr>(handle);
+ if (!priv) return;
+ std::string Clearkey{key};
+ priv->renderer->SetDrmLicenseKey(
+ plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type),
+ Clearkey);
+}
+
int trackrenderer_set_display_mode(TrackRendererHandle handle,
TrackRendererDisplayMode mode) {
auto priv = static_cast<TrackRendererPrivPtr>(handle);
return kSuccess;
}
-int trackrenderer_set_display_ecore_wl2_subsurface(
- TrackRendererHandle handle, TrackRendererDisplayType type,
- void* ecore_wl2_subsurface, int x, int y, int w, int h) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- if (!ecore_wl2_subsurface) return kFailed;
- if (priv->renderer->SetDisplaySubsurface(
- plusplayer::trackrenderer::capi_utils::ConvertToDisplayType(type),
- ecore_wl2_subsurface, x, y, w, h) == false) {
- return kFailed;
- }
- return kSuccess;
-}
-
int trackrenderer_set_display_roi(TrackRendererHandle handle,
TrackRendererGeometry* geometry) {
auto priv = static_cast<TrackRendererPrivPtr>(handle);
if (!priv) return kFailed;
- plusplayer::trackrenderer::Geometry result;
- plusplayer::trackrenderer::capi_utils::MakeGeometry(&result, *geometry);
- if (!priv->renderer->SetDisplayRoi(result)) {
+ plusplayer::trackrenderer::Geometry roi;
+ plusplayer::trackrenderer::capi_utils::MakeGeometry(&roi, *geometry);
+ if (!priv->renderer->SetDisplayRoi(roi)) {
return kFailed;
}
return kSuccess;
TrackRendererCropArea* crop) {
auto priv = static_cast<TrackRendererPrivPtr>(handle);
if (!priv) return kFailed;
- plusplayer::trackrenderer::CropArea result;
- plusplayer::trackrenderer::capi_utils::MakeCropArea(&result, *crop);
- if (!priv->renderer->SetVideoRoi(result)) {
- return kFailed;
- }
- return kSuccess;
-}
-
-int trackrenderer_resize_render_rect(TrackRendererHandle handle,
- TrackRendererRenderRect* rect) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- plusplayer::trackrenderer::RenderRect result;
- plusplayer::trackrenderer::capi_utils::MakeRenderRect(&result, *rect);
- if (!priv->renderer->ResizeRenderRect(result)) {
+ plusplayer::trackrenderer::CropArea area;
+ plusplayer::trackrenderer::capi_utils::MakeCropArea(&area, *crop);
+ if (!priv->renderer->SetVideoRoi(area)) {
return kFailed;
}
return kSuccess;
}
return kSuccess;
}
-
void trackrenderer_set_video_frame_buffer_type(
TrackRendererHandle handle, TrackRendererDecodedVideoFrameBufferType type) {
auto priv = static_cast<TrackRendererPrivPtr>(handle);
type));
}
-void trackrenderer_set_video_frame_buffer_type_ext(
- TrackRendererHandle handle,
- TrackRendererDecodedVideoFrameBufferTypeExt type) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->renderer->SetVideoFrameBufferType(
- plusplayer::trackrenderer::capi_utils::ConvertToVideoFrameBufferTypeExt(
- type));
-}
-
-int trackrenderer_set_video_frame_buffer_scale_resolution(
- TrackRendererHandle handle, uint32_t target_width, uint32_t target_height) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- if (!target_width || !target_height) return kFailed;
- priv->renderer->SetVideoFrameBufferScaleResolution(target_width,
- target_height);
- return kSuccess;
-}
-
-int trackrenderer_set_decoded_video_frame_rate(
- TrackRendererHandle handle, TrackRendererRational request_framerate) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- plusplayer::trackrenderer::Rational request_fps;
- plusplayer::trackrenderer::capi_utils::MakeRational(&request_fps,
- request_framerate);
- if (!priv->renderer->SetDecodedVideoFrameRate(request_fps)) {
- return kFailed;
- }
- return kSuccess;
-}
-
int trackrenderer_flush(TrackRendererHandle handle,
TrackRendererTrackType type) {
auto priv = static_cast<TrackRendererPrivPtr>(handle);
if (!priv) return kFailed;
priv->renderer->FlushAppsrc(
- plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type), true);
+ plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type));
return kSuccess;
}
return kSuccess;
}
-int trackrenderer_set_aifilter(TrackRendererHandle handle, void* aifilter) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- if (!priv->renderer->SetAiFilter(aifilter)) {
- return kFailed;
- }
- return kSuccess;
-}
-
-int trackrenderer_set_catch_up_speed(TrackRendererHandle handle,
- const TrackRendererCatchUpSpeed level) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- priv->renderer->SetCatchUpSpeed(
- plusplayer::trackrenderer::capi_utils::ConvertToCatchUpSpeed(level));
- return kSuccess;
-}
-
-int trackrenderer_get_video_latency_status(TrackRendererHandle handle,
- TrackRendererLatencyStatus* status) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
-
- plusplayer::trackrenderer::LatencyStatus current =
- plusplayer::trackrenderer::LatencyStatus::kLow;
- priv->renderer->GetVideoLatencyStatus(¤t);
- *status = plusplayer::trackrenderer::capi_utils::
- ConvertToTrackrendererLatencyStatus(current);
- return kSuccess;
-}
-
-int trackrenderer_get_audio_latency_status(TrackRendererHandle handle,
- TrackRendererLatencyStatus* status) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
-
- plusplayer::trackrenderer::LatencyStatus current =
- plusplayer::trackrenderer::LatencyStatus::kLow;
- priv->renderer->GetAudioLatencyStatus(¤t);
- *status = plusplayer::trackrenderer::capi_utils::
- ConvertToTrackrendererLatencyStatus(current);
- return kSuccess;
-}
-
-int trackrenderer_set_video_mid_latency_threshold(
- TrackRendererHandle handle, const unsigned int threshold) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
-
- priv->renderer->SetVideoMidLatencyThreshold(threshold);
- return kSuccess;
-}
-
-int trackrenderer_set_audio_mid_latency_threshold(
- TrackRendererHandle handle, const unsigned int threshold) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
-
- priv->renderer->SetAudioMidLatencyThreshold(threshold);
- return kSuccess;
-}
-
-int trackrenderer_set_video_high_latency_threshold(
- TrackRendererHandle handle, const unsigned int threshold) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
-
- priv->renderer->SetVideoHighLatencyThreshold(threshold);
- return kSuccess;
-}
-
-int trackrenderer_set_audio_high_latency_threshold(
- TrackRendererHandle handle, const unsigned int threshold) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
-
- priv->renderer->SetAudioHighLatencyThreshold(threshold);
- return kSuccess;
-}
-
/* CALL back*/
void trackrenderer_set_error_cb(TrackRendererHandle handle,
trackrenderer_error_cb callback,
priv->error_cb_userdata = userdata;
}
-void trackrenderer_set_error_msg_cb(TrackRendererHandle handle,
- trackrenderer_error_msg_cb callback,
- void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->error_msg_cb = callback;
- priv->error_msg_cb_userdata = userdata;
-}
-
void trackrenderer_set_resourceconflict_cb(
TrackRendererHandle handle, trackrenderer_resource_conflicted_cb callback,
void* userdata) {
priv->event_cb_userdata = userdata;
}
-void trackrenderer_set_first_decoding_done_cb(
- TrackRendererHandle handle, trackrenderer_first_decoding_done_cb callback,
- void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->first_decoding_done_cb = callback;
- priv->first_decoding_done_cb_userdata = userdata;
-}
-
void trackrenderer_set_subtitle_rawdata_cb(
TrackRendererHandle handle, trackrenderer_subtitle_rawdata_cb callback,
void* userdata) {
priv->seekdata_cb_userdata = userdata;
}
-void trackrenderer_set_media_packet_video_tbmptr_cb(
- TrackRendererHandle handle,
- trackrenderer_media_packet_video_tbmptr_cb callback, void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->video_tbmptr_cb = callback;
- priv->video_tbmptr_cb_userdata = userdata;
-}
-
void trackrenderer_set_media_packet_video_decoded_cb(
TrackRendererHandle handle,
trackrenderer_media_packet_video_decoded_cb callback, void* userdata) {
priv->video_decoded_cb = callback;
priv->video_decoded_cb_userdata = userdata;
}
-
-void trackrenderer_set_media_packet_video_raw_decoded_cb(
- TrackRendererHandle handle,
- trackrenderer_media_packet_video_raw_decoded_cb callback, void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->video_raw_decoded_cb = callback;
- priv->video_raw_decoded_cb_userdata = userdata;
-}
-
-void trackrenderer_set_video_decoder_underrun_cb(
- TrackRendererHandle handle, trackrenderer_decoder_underrun_cb callback,
- void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->video_decoder_underrun_cb = callback;
- priv->video_decoder_underrun_cb_userdata = userdata;
-}
-
-int trackrenderer_set_alternative_audio_resource(TrackRendererHandle handle,
- unsigned int rsc_type) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
-
- priv->renderer->SetAlternativeAudioResource(rsc_type);
- return kSuccess;
-}
-
-void trackrenderer_set_video_latency_status_cb(
- TrackRendererHandle handle, trackrenderer_video_latency_status_cb callback,
- void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->video_latency_status_cb = callback;
- priv->video_latency_status_cb_userdata = userdata;
-}
-
-void trackrenderer_set_audio_latency_status_cb(
- TrackRendererHandle handle, trackrenderer_audio_latency_status_cb callback,
- void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->audio_latency_status_cb = callback;
- priv->audio_latency_status_cb_userdata = userdata;
-}
-
-void trackrenderer_set_video_high_latency_cb(
- TrackRendererHandle handle, trackrenderer_video_high_latency_cb callback,
- void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->video_high_latency_cb = callback;
- priv->video_high_latency_cb_userdata = userdata;
-}
-
-void trackrenderer_set_audio_high_latency_cb(
- TrackRendererHandle handle, trackrenderer_audio_high_latency_cb callback,
- void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->audio_high_latency_cb = callback;
- priv->audio_high_latency_cb_userdata = userdata;
-}
-
-void trackrenderer_set_multiview_start_video_cb(
- TrackRendererHandle handle, trackrenderer_multiview_start_video_cb callback,
- void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->multiview_start_video_cb = callback;
- priv->multiview_start_video_cb_userdata = userdata;
-}
-
-void trackrenderer_set_multiview_stop_video_cb(
- TrackRendererHandle handle, trackrenderer_multiview_stop_video_cb callback,
- void* userdata) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return;
- priv->multiview_stop_video_cb = callback;
- priv->multiview_stop_video_cb_userdata = userdata;
-}
-
-int trackrenderer_init_audio_easing_info(
- TrackRendererHandle handle, const uint32_t init_volume,
- const uint32_t init_elapsed_time,
- const TrackRendererAudioEasingInfo* easing_info) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
-
- plusplayer::trackrenderer::AudioEasingInfo info;
- plusplayer::trackrenderer::capi_utils::MakeAudioEasingInfo(&info,
- easing_info);
- if (!priv->renderer->InitAudioEasingInfo(init_volume, init_elapsed_time,
- info)) {
- return kFailed;
- }
- return kSuccess;
-}
-
-int trackrenderer_update_audio_easing_info(
- TrackRendererHandle handle,
- const TrackRendererAudioEasingInfo* easing_info) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- plusplayer::trackrenderer::AudioEasingInfo info;
- plusplayer::trackrenderer::capi_utils::MakeAudioEasingInfo(&info,
- easing_info);
- if (!priv->renderer->UpdateAudioEasingInfo(info)) {
- return kFailed;
- }
- return kSuccess;
-}
-
-int trackrenderer_get_audio_easing_info(
- TrackRendererHandle handle, uint32_t* current_volume,
- uint32_t* elapsed_time, TrackRendererAudioEasingInfo* easing_info) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- plusplayer::trackrenderer::AudioEasingInfo info;
- if (!priv->renderer->GetAudioEasingInfo(current_volume, elapsed_time,
- &info)) {
- return kFailed;
- }
- plusplayer::trackrenderer::capi_utils::MakeTrackRendererAudioEasingInfo(
- easing_info, info);
- return kSuccess;
-}
-
-int trackrenderer_start_audio_easing(TrackRendererHandle handle) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
-
- if (!priv->renderer->StartAudioEasing()) {
- return kFailed;
- }
- return kSuccess;
-}
-
-int trackrenderer_stop_audio_easing(TrackRendererHandle handle) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
-
- if (!priv->renderer->StopAudioEasing()) {
- return kFailed;
- }
- return kSuccess;
-}
-
-int trackrenderer_get_virtual_rsc_id(TrackRendererHandle handle,
- TrackRendererRscType type,
- int* virtual_id) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- plusplayer::trackrenderer::RscType converted_type =
- plusplayer::trackrenderer::RscType::kVideoRenderer;
- if (!plusplayer::trackrenderer::capi_utils::ConvertToRscType(type,
- &converted_type))
- return kFailed;
- if (!priv->renderer->GetVirtualRscId(converted_type, virtual_id)) {
- return kFailed;
- }
- return kSuccess;
-}
-
-int trackrenderer_set_advanced_picture_quality_type(
- TrackRendererHandle handle, TrackRendererAdvPictureQualityType type) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- plusplayer::trackrenderer::AdvPictureQualityType converted_type =
- plusplayer::trackrenderer::AdvPictureQualityType::kVideoCall;
- if (!plusplayer::trackrenderer::capi_utils::ConvertToAdvPictureQualityType(
- type, &converted_type))
- return kFailed;
- if (!priv->renderer->SetAdvancedPictureQualityType(converted_type)) {
- return kFailed;
- }
- return kSuccess;
-}
-
-int trackrenderer_set_resource_allocate_policy(
- TrackRendererHandle handle, TrackRendererRscAllocPolicy policy) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- plusplayer::trackrenderer::RscAllocPolicy converted_policy =
- plusplayer::trackrenderer::RscAllocPolicy::kRscAllocExclusive;
- if (!plusplayer::trackrenderer::capi_utils::ConvertToRscAllocPolicy(
- policy, &converted_policy))
- return kFailed;
- if (!priv->renderer->SetResourceAllocatePolicy(converted_policy)) {
- return kFailed;
- }
- return kSuccess;
-}
-
-int trackrenderer_set_video_renderer_type(
- TrackRendererHandle handle, TrackRendererVideoRendererType renderer_type) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- plusplayer::trackrenderer::ResourceCategory converted_renderer_type;
- if (!plusplayer::trackrenderer::capi_utils::ConvertToVideoRendererType(
- renderer_type, &converted_renderer_type))
- return kFailed;
- if (!priv->renderer->SetVideoRendererType(converted_renderer_type)) {
- return kFailed;
- }
- return kSuccess;
-}
-
-int trackrenderer_set_video_par_dar(TrackRendererHandle handle,
- uint64_t time_millisecond, uint32_t par_num,
- uint32_t par_den, uint32_t dar_num,
- uint32_t dar_den) {
- auto priv = static_cast<TrackRendererPrivPtr>(handle);
- if (!priv) return kFailed;
- priv->renderer->SetVideoParDar(time_millisecond, par_num, par_den, dar_num,
- dar_den);
- return kSuccess;
-}
properties.license_acquired_userdata;
}
-void MakeGeometry(Geometry* output, const TrackRendererGeometry& input) {
- output->x = input.x;
- output->y = input.y;
- output->w = input.w;
- output->h = input.h;
+void MakeGeometry(Geometry* roi, const TrackRendererGeometry& geometry) {
+ roi->x = geometry.x;
+ roi->y = geometry.y;
+ roi->w = geometry.w;
+ roi->h = geometry.h;
}
-void MakeCropArea(CropArea* output, const TrackRendererCropArea& input) {
- output->scale_x = input.scale_x;
- output->scale_y = input.scale_y;
- output->scale_w = input.scale_w;
- output->scale_h = input.scale_h;
-}
-
-void MakeRenderRect(RenderRect* output, const TrackRendererRenderRect& input) {
- output->x = input.x;
- output->y = input.y;
- output->w = input.w;
- output->h = input.h;
+void MakeCropArea(CropArea* area, const TrackRendererCropArea& crop) {
+ area->scale_x = crop.scale_x;
+ area->scale_y = crop.scale_y;
+ area->scale_w = crop.scale_w;
+ area->scale_h = crop.scale_h;
}
std::map<std::string, bool> MakeIniProperty(
return iniproperty;
}
+std::map<std::string, std::string> MakeIniElement(
+ TrackRendererIniElement* elements, int size) {
+ std::map<std::string, std::string> inielement;
+ for (int index = 0; index < size; index++) {
+ inielement.insert(std::pair<std::string, std::string>(elements[index].key,
+ elements[index].value));
+ }
+ return inielement;
+}
+
std::vector<Track> MakeTrack(const TrackRendererTrack* trackrenderertrack,
const int size) {
std::vector<Track> trackvector;
if (track_util::IsValidCodecDataSize(
trackrenderertrack[index].codec_data_len)) {
track.codec_data = std::shared_ptr<char>(
- new char[trackrenderertrack[index].codec_data_len],
- std::default_delete<char[]>());
+ new char[trackrenderertrack[index].codec_data_len]);
memcpy(track.codec_data.get(), trackrenderertrack[index].codec_data,
trackrenderertrack[index].codec_data_len);
track.codec_data_len = trackrenderertrack[index].codec_data_len;
track.subtitle_format = trackrenderertrack[index].subtitle_format
? trackrenderertrack[index].subtitle_format
: "";
- trackvector.push_back(std::move(track));
- }
- return trackvector;
-}
+ track.stream_format = trackrenderertrack[index].stream_format
+ ? trackrenderertrack[index].stream_format
+ : "";
+ track.alignment = trackrenderertrack[index].alignment
+ ? trackrenderertrack[index].alignment
+ : "";
+ track.original_media_type = trackrenderertrack[index].original_media_type
+ ? trackrenderertrack[index].original_media_type
+ : "";
+ track.protection_system = trackrenderertrack[index].protection_system
+ ? trackrenderertrack[index].protection_system
+ : "";
-std::vector<Track> MakeTrackFromTrackHandle(
- const TrackRendererTrackHandle* track_handle, const int size) {
- std::vector<Track> trackvector;
- for (int index = 0; index < size; index++) {
- trackvector.push_back(*static_cast<Track*>(track_handle[index]));
+ trackvector.push_back(std::move(track));
}
return trackvector;
}
geometry->h = roi.h;
}
-// LCOV_EXCL_START
#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
void MakeTrackRendererSubtitleAttr(TrackRendererSubtitleAttr* attr,
const SubtitleAttr& input_attr) {
}
}
#endif
-// LCOV_EXCL_STOP
void MakePlayerAppInfo(const TrackRendererAppInfo* app_attr,
PlayerAppInfo& app_info) {
case kTrackRendererDrmTypeWidevineCdm: {
return drm::Type::kWidevineCdm;
}
+ case kTrackRendererDrmTypeClearkey: {
+ return drm::Type::kClearkey;
+ }
case kTrackRendererDrmTypeDrmMax: {
return drm::Type::kMax;
}
}
}
-// LCOV_EXCL_START
TrackRendererErrorType ConvertToTrackRendererErrorType(ErrorType type) {
switch (type) {
case ErrorType::kNone: {
}
}
-TrackRendererEventType ConvertToTrackRendererEventType(const EventType& event) {
- switch (event) {
- case EventType::kNone: {
+TrackRendererEventType ConvertToTrackRendererEventType(const EventType& event){
+ switch (event){
+ case EventType::kNone:{
return kTrackRendererEventTypeNone;
}
- case EventType::kResolutionChanged: {
+ case EventType::kResolutionChanged:{
return kTrackRendererEventTypeResolutionChanged;
}
default:
return kTrackRendererEventTypeNone;
}
}
-// LCOV_EXCL_STOP
#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
TrackRendererSubtitleAttrType ConvertToTrackRendererSubtitleAttrType(
case kTrackRendererDecodedVideoFrameBufferReference: {
return DecodedVideoFrameBufferType::kReference;
}
- case kTrackRendererDecodedVideoFrameBufferScale: {
- return DecodedVideoFrameBufferType::kScale;
- }
case kTrackRendererDecodedVideoFrameBufferNone: {
return DecodedVideoFrameBufferType::kNone;
}
return DecodedVideoFrameBufferType::kNone;
}
}
-DecodedVideoFrameBufferType ConvertToVideoFrameBufferTypeExt(
- const TrackRendererDecodedVideoFrameBufferTypeExt& type) {
- switch (type) {
- case kTrackRendererDecodedVideoFrameBufferExtNone: {
- return DecodedVideoFrameBufferType::kNone;
- }
- case kTrackRendererDecodedVideoFrameBufferExtRaw: {
- return DecodedVideoFrameBufferType::kRaw;
- }
- default:
- TRACKRENDERER_ERROR("wrong buffer type");
- return DecodedVideoFrameBufferType::kNone;
- }
-}
-
-CatchUpSpeed ConvertToCatchUpSpeed(const TrackRendererCatchUpSpeed& level) {
- switch (level) {
- case kTrackRendererCatchUpSpeedNone: {
- return CatchUpSpeed::kNone;
- }
- case kTrackRendererCatchUpSpeedSlow: {
- return CatchUpSpeed::kSlow;
- }
- case kTrackRendererCatchUpSpeedNormal: {
- return CatchUpSpeed::kMid;
- }
- case kTrackRendererCatchUpSpeedFast: {
- return CatchUpSpeed::kFast;
- }
- }
- TRACKRENDERER_ERROR("Unknown catch up speed");
- return CatchUpSpeed::kNone;
-}
-
-TrackRendererLatencyStatus ConvertToTrackrendererLatencyStatus(
- const LatencyStatus& status) {
- switch (status) {
- case LatencyStatus::kLow: {
- return kTrackRendererLatencyStatusLow;
- }
- case LatencyStatus::kMid: {
- return kTrackRendererLatencyStatusMid;
- }
- case LatencyStatus::kHigh: {
- return kTrackRendererLatencyStatusHigh;
- }
- default:
- TRACKRENDERER_ERROR("Unknown latency status");
- return kTrackRendererLatencyStatusLow;
- }
-}
-
-AudioEasingType ConvertToAudioEasingType(
- const TrackRendererAudioEasingType& type) {
- switch (type) {
- case kTrackRendererAudioEasingLinear: {
- return AudioEasingType::kAudioEasingLinear;
- }
- case kTrackRendererAudioEasingIncubic: {
- return AudioEasingType::kAudioEasingIncubic;
- }
- case kTrackRendererAudioEasingOutcubic: {
- return AudioEasingType::kAudioEasingOutcubic;
- }
- default:
- TRACKRENDERER_ERROR("wrong audio easing type");
- return AudioEasingType::kAudioEasingNone;
- }
-}
-
-TrackRendererAudioEasingType ConvertToTrackRendererAudioEasingType(
- const AudioEasingType& type) {
- switch (type) {
- case AudioEasingType::kAudioEasingLinear: {
- return kTrackRendererAudioEasingLinear;
- }
- case AudioEasingType::kAudioEasingIncubic: {
- return kTrackRendererAudioEasingIncubic;
- }
- case AudioEasingType::kAudioEasingOutcubic: {
- return kTrackRendererAudioEasingOutcubic;
- }
- default:
- TRACKRENDERER_ERROR("wrong audio easing type");
- return kTrackRendererAudioEasingNone;
- }
-}
-
-void MakeAudioEasingInfo(AudioEasingInfo* easing_info,
- const TrackRendererAudioEasingInfo* easing_attr) {
- easing_info->target_volume = easing_attr->target_volume;
- easing_info->duration = easing_attr->duration;
- easing_info->type = ConvertToAudioEasingType(easing_attr->type);
-}
-
-void MakeTrackRendererAudioEasingInfo(TrackRendererAudioEasingInfo* easing_attr,
- const AudioEasingInfo& easing_info) {
- easing_attr->target_volume = easing_info.target_volume;
- easing_attr->duration = easing_info.duration;
- easing_attr->type = ConvertToTrackRendererAudioEasingType(easing_info.type);
-}
-
-bool ConvertToRscType(const TrackRendererRscType& typevalue, RscType* type) {
- switch (typevalue) {
- case kTrackRendererRscTypeVideoRenderer:
- *type = RscType::kVideoRenderer;
- return true;
- default:
- TRACKRENDERER_ERROR("unknown resource type");
- return false;
- }
-}
-
-bool ConvertToAdvPictureQualityType(
- const TrackRendererAdvPictureQualityType& typevalue,
- AdvPictureQualityType* type) {
- switch (typevalue) {
- case kTrackRendererAdvPictureQualityTypeVideoCall:
- *type = AdvPictureQualityType::kVideoCall;
- return true;
- case kTrackRendererAdvPictureQualityTypeUsbCamera:
- *type = AdvPictureQualityType::kUsbCamera;
- return true;
- default:
- TRACKRENDERER_ERROR("unknown resource type");
- return false;
- }
-}
-
-bool ConvertToRscAllocPolicy(const TrackRendererRscAllocPolicy& policyvalue,
- RscAllocPolicy* policy) {
- switch (policyvalue) {
- case kTrackRendererRscAllocExclusive:
- *policy = RscAllocPolicy::kRscAllocExclusive;
- return true;
- case kTrackRendererRscAllocConditional:
- *policy = RscAllocPolicy::kRscAllocConditional;
- return true;
- default:
- TRACKRENDERER_ERROR("unknown policy");
- return false;
- }
-}
-
-void MakeRational(Rational* rational_info,
- const TrackRendererRational& rational_attr) {
- if (!rational_info) return;
- rational_info->num = rational_attr.num;
- rational_info->den = rational_attr.den;
-}
-
-bool ConvertToVideoRendererType(
- const TrackRendererVideoRendererType& renderer_type,
- ResourceCategory* rsc_category) {
- if (rsc_category == nullptr) return false;
- bool ret = true;
- if (renderer_type == TrackRendererVideoRendererTypeMain) {
- *rsc_category = ResourceCategory::kVideoRenderer;
- } else if (renderer_type == TrackRendererVideoRendererTypeSub) {
- *rsc_category = ResourceCategory::kVideoRendererSub;
- } else if (renderer_type == TrackRendererVideoRendererTypeSub2) {
- *rsc_category = ResourceCategory::kVideoRendererSub2;
- } else if (renderer_type == TrackRendererVideoRendererTypeSub3) {
- *rsc_category = ResourceCategory::kVideoRendererSub3;
- } else {
- ret = false;
- }
- return ret;
-}
} // namespace capi_utils
case drm::Type::kWidevineCdm:
drm_type = "WIDEVINE CDM";
break;
+ case drm::Type::kClearkey:
+ drm_type = "CLEARKEY";
+ break;
default:
drm_type = "";
break;
+++ /dev/null
-//
-// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#include "trackrenderer/trackrenderer_vconf.h"
-
-#include <algorithm>
-
-#include "json/json.h"
-#include "trackrenderer/core/utils/log.h"
-
-namespace plusplayer {
-
-namespace trackrenderer {
-
-Vconf::Vconf() {
- VconfCbList vconf_cb_list;
- vconf_map_[kPowerAnimationVconf] = vconf_cb_list;
-}
-
-Vconf::~Vconf() {
- vconf_map_[kPowerAnimationVconf].clear();
- vconf_map_.clear();
-}
-
-bool Vconf::IsMultiscreenMode() {
- TRACKRENDERER_ENTER
- char* mls_json_info = vconf_get_str(kMultiscreenInfoVconf);
- if (NULL == mls_json_info) {
- TRACKRENDERER_ERROR("Fail to get memory/multiscreen/info vconf info.");
- return false;
- }
- bool ret = ParseMlsVconf_(mls_json_info);
- free(mls_json_info);
-
- return ret;
-}
-
-void Vconf::SetVconfsCb(const std::vector<std::string>& names,
- vconf_cb callback, void* userdata) {
- TRACKRENDERER_ENTER
- if (names.empty() || nullptr == callback || nullptr == userdata) return;
-
- std::lock_guard<std::mutex> lk(vconf_m_);
- for (auto& name : names) {
- SetVconfCb_(name, callback, userdata);
- }
- TRACKRENDERER_LEAVE
-}
-
-void Vconf::UnsetVconfsCb(const std::vector<std::string>& names,
- vconf_cb callback, void* userdata) {
- if (names.empty() || nullptr == callback || nullptr == userdata) return;
-
- std::lock_guard<std::mutex> lk(vconf_m_);
- for (auto& name : names) {
- UnsetVconfCb_(name, callback, userdata);
- }
-}
-
-void Vconf::VconfCb_(keynode_t* key, void* userdata) {
- TRACKRENDERER_ENTER
- Vconf* vf = static_cast<Vconf*>(userdata);
- if (nullptr == vf) return;
- char* name = vconf_keynode_get_name(key);
- if (nullptr == name) {
- TRACKRENDERER_ERROR("vconf name is NULL!");
- return;
- }
-
- TRACKRENDERER_INFO("vconf name[%s]", name);
- std::string vf_name(name);
- std::string value;
- if (vf_name == kPowerAnimationVconf) {
- int vf_value = vconf_keynode_get_int(key);
- TRACKRENDERER_INFO("vconf memory/welcome_mode/power_animation, value[%d]",
- vf_value);
- if (vf_value > 1 || vf_value < 0) {
- TRACKRENDERER_WARN("Skip power_animation vconf value[%d]", vf_value);
- return;
- }
- int smsrc_status = 0;
- if (vconf_get_int(kTV2MobileStateVconf, &smsrc_status)) {
- TRACKRENDERER_ERROR("Fail to get[%s] value!", kTV2MobileStateVconf);
- return;
- }
- if (smsrc_status) {
- TRACKRENDERER_WARN("Skip TV2Mobile state[%d]", smsrc_status);
- return;
- }
-
- value = (vf_value == 1) ? "true" : "false";
- } else {
- TRACKRENDERER_ERROR("Unknow vconf name: %s", name);
- return;
- }
-
- vf->Notify_(vf_name, value);
- TRACKRENDERER_LEAVE
-}
-
-void Vconf::Notify_(const std::string& name, const std::string& value) {
- TRACKRENDERER_ENTER
- std::lock_guard<std::mutex> lk(vconf_m_);
- TRACKRENDERER_INFO("name[%s], value[%s]", name.c_str(), value.c_str());
- for (auto& item : vconf_map_[name]) {
- if (item.first) {
- item.first(name, value, item.second);
- TRACKRENDERER_INFO("Notify user[%p]", item.second);
- }
- }
- TRACKRENDERER_LEAVE
-}
-
-void Vconf::SetVconfCb_(const std::string& name, vconf_cb callback,
- void* userdata) {
- TRACKRENDERER_INFO("name[%s], callback[%p], userdata[%p]", name.c_str(),
- callback, userdata);
- if (vconf_map_.count(name) == 0) {
- TRACKRENDERER_ERROR("Not support vconf[%s]", name.c_str());
- return;
- }
- if (vconf_map_[name].empty()) {
- int ret = vconf_notify_key_changed(name.c_str(), Vconf::VconfCb_, this);
- if (ret < 0) {
- TRACKRENDERER_ERROR("vconf_notify_key_changed() return error[%d]", ret);
- return;
- }
- TRACKRENDERER_INFO("Register vconf[%s] successfully", name.c_str());
- }
-
- auto is_exist = [callback, userdata](const VconfPair& item) {
- return (callback == item.first) && (userdata == item.second);
- };
- auto target =
- std::find_if(vconf_map_[name].begin(), vconf_map_[name].end(), is_exist);
- if (target != vconf_map_[name].end()) {
- TRACKRENDERER_ERROR("User[%p] has existed!", userdata);
- return;
- }
- vconf_map_[name].push_back(std::make_pair(callback, userdata));
-}
-
-void Vconf::UnsetVconfCb_(const std::string& name, vconf_cb callback,
- void* userdata) {
- TRACKRENDERER_INFO("name[%s], callback[%p], userdata[%p]", name.c_str(),
- callback, userdata);
- if (vconf_map_.count(name) == 0) {
- TRACKRENDERER_ERROR("Not support vconf[%s]", name.c_str());
- return;
- }
- if (vconf_map_[name].empty()) return;
-
- auto is_exist = [callback, userdata](const VconfPair& item) {
- return (callback == item.first) && (userdata == item.second);
- };
- vconf_map_[name].remove_if(is_exist);
-
- if (vconf_map_[name].empty()) {
- int ret = vconf_ignore_key_changed(name.c_str(), Vconf::VconfCb_);
- if (ret < 0) {
- TRACKRENDERER_ERROR("vconf_ignore_key_changed() return error[%d]", ret);
- } else {
- TRACKRENDERER_INFO("Unregister vconf[%s] successfully.", name.c_str());
- }
- }
-}
-
-bool Vconf::ParseMlsVconf_(const char* json) {
- TRACKRENDERER_INFO("memory/multiscreen/info: %s", json);
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(json, root)) {
- TRACKRENDERER_ERROR(
- "Fail to parse memory/multiscreen/info content info[%s], error[%s]",
- json, (reader.getFormatedErrorMessages()).c_str());
- return false;
- }
- std::string mode = root["mode"].asString();
- TRACKRENDERER_INFO("Multiscreen mode[%s]", mode.c_str());
- return (mode == "on") ? true : false;
-}
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
+++ /dev/null
-//
-// @ Copyright [2021] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#include "trackrenderer/core/utils/log.h"
-#include "trackrenderer/vr360.h"
-
-#include <dlfcn.h>
-#include <mutex>
-namespace plusplayer {
-
-namespace trackrenderer {
-
-#define VR360_LIB_PATH "/usr/lib/libvr360.so"
-
-static std::once_flag lib_loaded;
-static void* vr360_lib = nullptr;
-
-static Vr360Initialize vr360_tz_initialize = nullptr;
-static Vr360Finalize vr360_tz_finalize = nullptr;
-static Vr360SetGpuMode vr360_tz_set_gpu_mode = nullptr;
-
-Vr360::Vr360() {
- auto loadlib = []() {
- TRACKRENDERER_ENTER
- vr360_lib = dlopen(VR360_LIB_PATH, RTLD_LAZY);
- if (!vr360_lib) {
- TRACKRENDERER_ERROR("libvr360.so open failed: %s", dlerror());
- return;
- }
- vr360_tz_initialize =
- (Vr360Initialize)dlsym(vr360_lib, "vr360_tz_initialize");
- if (!vr360_tz_initialize) {
- TRACKRENDERER_ERROR("Failed to import vr360_tz_initialize");
- return;
- }
- vr360_tz_finalize = (Vr360Finalize)dlsym(vr360_lib, "vr360_tz_finalize");
- if (!vr360_tz_finalize) {
- TRACKRENDERER_ERROR("Failed to import vr360_tz_finalize");
- return;
- }
- vr360_tz_set_gpu_mode =
- (Vr360SetGpuMode)dlsym(vr360_lib, "vr360_tz_set_gpu_mode");
- if (!vr360_tz_set_gpu_mode) {
- TRACKRENDERER_ERROR("Failed to import vr360_tz_set_gpu_mode");
- return;
- }
- };
- std::call_once(lib_loaded, loadlib);
-}
-
-Vr360::~Vr360() {}
-
-void Vr360::Vr360TzSetGpuMode(bool set) {
- TRACKRENDERER_ENTER
- if (vr360_tz_initialize == nullptr || vr360_tz_finalize == nullptr ||
- vr360_tz_set_gpu_mode == nullptr)
- return;
- vr360_tz_initialize(&vr360_tz_handle_);
- if (set) {
- vr360_tz_set_gpu_mode(vr360_tz_handle_,
- static_cast<int>(GpuMode::kVr360GpuModeSecure));
- } else {
- vr360_tz_set_gpu_mode(vr360_tz_handle_,
- static_cast<int>(GpuMode::kVr360GpuModeNonSecure));
- }
- vr360_tz_finalize(vr360_tz_handle_);
- vr360_tz_handle_ = nullptr;
- TRACKRENDERER_LEAVE
-}
-
-} // namespace trackrenderer
-
-} // namespace plusplayer
+++ /dev/null
-unit_test/ut_plusplayer_all.xml
\ No newline at end of file
+++ /dev/null
-unit_test/ut_plusplayer_1.xml
\ No newline at end of file
+++ /dev/null
-unit_test/ut_plusplayer_2.xml
\ No newline at end of file
+++ /dev/null
-unit_test/ut_plusplayer_3.xml
\ No newline at end of file
+++ /dev/null
-unit_test/ut_plusplayer_4.xml
\ No newline at end of file
+++ /dev/null
-unit_test/ut_plusplayer_5.xml
\ No newline at end of file
+++ /dev/null
-unit_test/ut_plusplayer_6.xml
\ No newline at end of file
+++ /dev/null
-unit_test/ut_plusplayer_7.xml
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<TestFarm>
- <Target AssignTargets="1">
- <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_1.dat"/>
- </Target>
- <Target AssignTargets="1">
- <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_2.dat"/>
- </Target>
- <Target AssignTargets="1">
- <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_3.dat"/>
- </Target>
- <Target AssignTargets="1">
- <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_4.dat"/>
- </Target>
- <Target AssignTargets="1">
- <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_5.dat"/>
- </Target>
- <Target AssignTargets="1">
- <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_6.dat"/>
- </Target>
- <Target AssignTargets="1">
- <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_7.dat"/>
- </Target>
-</TestFarm>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
- <Procedure Number="1" Description="Plusplayer unit test - 1/7">
- <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml" Permission="ROOT">
- <Input Expirytime="600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
- </Step>
-
- <Step Name="Plusplayer unit test - step : 1" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=0;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_1.xml" Permission="ROOT">
- <Input Expirytime="3600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_1.xml"/>
- </Step>
- </Procedure>
-</TestCase>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
- <Procedure Number="1" Description="Plusplayer unit test - 2/7">
- <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml" Permission="ROOT">
- <Input Expirytime="600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
- </Step>
-
- <Step Name="Plusplayer unit test - step : 2" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=1;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_2.xml" Permission="ROOT">
- <Input Expirytime="3600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_2.xml"/>
- </Step>
- </Procedure>
-</TestCase>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
- <Procedure Number="1" Description="Plusplayer unit test - 3/7">
- <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml" Permission="ROOT">
- <Input Expirytime="600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
- </Step>
-
- <Step Name="Plusplayer unit test - step : 3" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=2;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_3.xml" Permission="ROOT">
- <Input Expirytime="3600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_3.xml"/>
- </Step>
- </Procedure>
-</TestCase>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
- <Procedure Number="1" Description="Plusplayer unit test - 4/7">
- <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml" Permission="ROOT">
- <Input Expirytime="600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
- </Step>
-
- <Step Name="Plusplayer unit test - step : 4" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=3;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_4.xml" Permission="ROOT">
- <Input Expirytime="3600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_4.xml"/>
- </Step>
- </Procedure>
-</TestCase>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
- <Procedure Number="1" Description="Plusplayer unit test - 5/7">
- <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml" Permission="ROOT">
- <Input Expirytime="600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
- </Step>
-
- <Step Name="Plusplayer unit test - step : 5" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=4;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_5.xml" Permission="ROOT">
- <Input Expirytime="3600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_5.xml"/>
- </Step>
- </Procedure>
-</TestCase>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
- <Procedure Number="1" Description="Plusplayer unit test - 6/7">
- <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml" Permission="ROOT">
- <Input Expirytime="600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
- </Step>
-
- <Step Name="Plusplayer unit test - step : 6" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=5;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_6.xml" Permission="ROOT">
- <Input Expirytime="3600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_6.xml"/>
- </Step>
- </Procedure>
-</TestCase>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
- <Procedure Number="1" Description="Plusplayer unit test - 7/7">
- <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml" Permission="ROOT">
- <Input Expirytime="600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
- </Step>
-
- <Step Name="Plusplayer unit test - step : 7" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=6;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_7.xml" Permission="ROOT">
- <Input Expirytime="3600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_7.xml"/>
- </Step>
- </Procedure>
-</TestCase>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
- <Procedure Number="1" Description="Plusplayer unit test">
- <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml" Permission="ROOT">
- <Input Expirytime="600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
- </Step>
-
- <Step Name="Plusplayer unit test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result.xml" Permission="ROOT">
- <Input Expirytime="3600"/>
- <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result.xml"/>
- </Step>
- </Procedure>
-</TestCase>
+++ /dev/null
-SET(fw_name "${PROJECT_NAME}_ut")
-
-SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
-SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
-
-SET(${fw_name}_CXXFLAGS "-Wall -Werror -std=c++11 -pthread -fPIE -Wl,-z,relro -fstack-protector -fno-delete-null-pointer-checks -DEFL_BETA_API_SUPPORT")
-
-SET(${fw_name}_LDFLAGS)
-
-SET(ADD_LIBS
- "trackrenderer"
- "gstvideo-1.0"
-)
-
-SET(dependents "gstreamer-1.0 glib-2.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 dlog gtest_gmock"
- "boost"
- "tv-resource-information tv-resource-manager libresourced appcore-efl elementary ecore evas ecore-wl2 audio-control"
- "capi-media-player"
- )
-IF(SUPPORT_SOUNDBAR)
-SET(dependents ${dependents} "libavoc-av")
-ELSE(SUPPORT_SOUNDBAR)
-SET(dependents ${dependents} "libavoc")
-ENDIF(SUPPORT_SOUNDBAR)
-
-INCLUDE(FindPkgConfig)
-IF(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
-pkg_check_modules(${fw_name} REQUIRED ${dependents})
-ELSE(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
-pkg_check_modules(${fw_name} REQUIRED ${dependents})
-ENDIF(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
-
-FOREACH(flag ${${fw_name}_CFLAGS})
-SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
-ENDFOREACH(flag)
-FOREACH(flag ${${fw_name}_CXXFLAGS})
-SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${EXTRA_CFLAGS} ${flag}")
-ENDFOREACH(flag)
-
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS}")
-
-INCLUDE_DIRECTORIES(
- ${PROJECT_SOURCE_DIR}/src
- ${PROJECT_SOURCE_DIR}/include
- ${PROJECT_SOURCE_DIR}
- ${PROJECT_SOURCE_DIR}/src/plusplayer-core/include_internal
- ${PROJECT_SOURCE_DIR}/src/plusplayer/include_internal
- ${PROJECT_SOURCE_DIR}/src/esplusplayer/include_internal
- ${PROJECT_SOURCE_DIR}/src/tracksource/include_internal
- ${PROJECT_SOURCE_DIR}/src/trackrenderer/include_internal
-)
-
-SET(UT_SRC
- # src/ut_defaultplayer.cpp
- # src/ut_espacket.cpp
- # src/ut_esplayer.cpp
- # src/ut_esplayer2.cpp
- # src/ut_esplayer_trackrenderer.cpp
- # src/ut_dashplayback.cpp
- # src/ut_display.cpp
- # src/ut_gst.cpp
- # src/ut_gstdashtracksource.cpp
- # src/ut_gsthlstracksource.cpp
- # src/ut_gsttrackrenderer.cpp
- # src/ut_gsttypefinder.cpp
- # src/ut_hlstracksource.cpp
- # src/ut_tracksource.cpp
- # src/ut_external_subtitle.cpp
- src/ut_main.cpp
- # src/ut_miscellaneous.cpp
- # src/ut_pipeline.cpp
- # src/ut_resource_manager.cpp
- # src/ut_serializer.cpp
- # src/ut_streamreader.cpp
- # src/ut_typefinder.cpp
- # src/ut_statemanager.cpp
- # src/ut_external_subtitle.cpp
- # src/ut_example.cpp
- # temporarily disabled - invalid tc , build errors : improve it or delete it
- # src/ut_trackrendereradapter.cpp
- # src/ut_trackrenderer.cpp
- # src/ut_trackrenderer_capi.cpp
- #src/esplusplayer/ut_basic.cpp
- #src/esplusplayer/ut_display.cpp
-)
-
-ADD_EXECUTABLE(${fw_name} ${UT_SRC})
-
-LINK_DIRECTORIES(${LIB_INSTALL_DIR})
-
-TARGET_LINK_LIBRARIES(${fw_name}
- ${CMAKE_THREAD_LIBS_INIT}
- ${ADD_LIBS}
- ${${fw_name}_LDFLAGS}
- "-pie"
-)
-
-INSTALL(
- TARGETS ${fw_name}
- DESTINATION bin
-)
+++ /dev/null
-**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
+++ /dev/null
-#!/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
+++ /dev/null
-//
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __PLUSPLAYER_UT_INCLUDE_APPWINDOW_H__
-#define __PLUSPLAYER_UT_INCLUDE_APPWINDOW_H__
-
-#define ECORE_WAYLAND_DISPLAY_TEST 1
-
-#include <chrono>
-#include <thread>
-
-#include "Ecore.h"
-#include "Elementary.h"
-#if ECORE_WAYLAND_DISPLAY_TEST
-#include "Ecore_Wl2.h"
-#endif
-
-namespace plusplayer_ut {
-
-class AppWindow {
- public:
- struct Window {
- Evas_Object* obj = nullptr;
- int x = 0, y = 0;
- int w = 0, h = 0; // width , height
- };
-
- AppWindow(int x, int y, int width, int height) : thread_init_done_(false) {
- window_.x = x, window_.y = y, window_.w = width, window_.h = height;
- thread_ = std::thread(AppWindow::WindowThread, this);
- while (!thread_init_done_) {
- std::this_thread::sleep_for(std::chrono::milliseconds(1));
- }
- }
-
- ~AppWindow() {
- ecore_thread_main_loop_begin();
- elm_exit();
- ecore_thread_main_loop_end();
- thread_.join();
- }
-
- static void WindowThread(AppWindow* appwindow) {
- elm_init(1, NULL);
- appwindow->CreateWindow_();
- appwindow->thread_init_done_ = true;
- elm_run();
- elm_shutdown();
- }
-
- Window GetWindow() { return window_; }
-
-#if ECORE_WAYLAND_DISPLAY_TEST
- Ecore_Wl2_Window* GetEcoreWL2Window() {
- return ecore_wl2_window_;
- }
-#endif
-
- private:
- void CreateWindow_() {
- ecore_thread_main_loop_begin();
-
- window_.obj = elm_win_add(NULL, "player", ELM_WIN_BASIC);
-
- assert(window_.obj && "window is NULL.");
-
- elm_win_title_set(window_.obj, "Plusplayer");
-
- elm_win_autodel_set(window_.obj, EINA_TRUE);
- elm_win_aux_hint_add(window_.obj, "wm.policy.win.user.geometry", "1");
- evas_object_move(window_.obj, window_.x, window_.y);
- evas_object_resize(window_.obj, window_.w, window_.h);
- evas_object_show(window_.obj);
-
-#if ECORE_WAYLAND_DISPLAY_TEST
- Ecore_Evas *ee =
- ecore_evas_ecore_evas_get(evas_object_evas_get(window_.obj));
- ecore_wl2_window_ = ecore_evas_wayland2_window_get(ee);
-#endif
- ecore_thread_main_loop_end();
- }
-
- private:
- bool thread_init_done_;
- Window window_;
-#if ECORE_WAYLAND_DISPLAY_TEST
- Ecore_Wl2_Window* ecore_wl2_window_;
-#endif
- std::thread thread_;
-};
-
-} // namespace plusplayer_ut
-
-#endif // __PLUSPLAYER_UT_INCLUDE_APPWINDOW_H__
+++ /dev/null
-//\r
-// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
-//\r
-\r
-#ifndef __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_EVENT_LISTENER_H__\r
-#define __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_EVENT_LISTENER_H__\r
-\r
-#include <string>\r
-#include <thread>\r
-#include <chrono>\r
-\r
-#include "ut/include/esplusplayer/esreader.hpp"\r
-#include "esplusplayer_capi/esplusplayer_capi.h"\r
-\r
-class EsPlayerEventCallback {
- public:
- EsPlayerEventCallback(esplusplayer_handle handle,\r
- EsStreamReader* video_reader,\r
- EsStreamReader* audio_reader)\r
- : handle_(handle), video_reader_(video_reader),\r
- audio_reader_(audio_reader) {}\r
- ~EsPlayerEventCallback() {\r
- if (audio_feeding_task_.joinable())\r
- audio_feeding_task_.join();\r
- if (video_feeding_task_.joinable())\r
- video_feeding_task_.join();\r
- }\r
- void SetCallback(void) {
- esplusplayer_set_error_cb(handle_, OnError, this);
- esplusplayer_set_buffer_status_cb(handle_, OnBufferStatus, this);
- esplusplayer_set_resource_conflicted_cb(handle_, OnResourceConflicted,
- this);
- esplusplayer_set_eos_cb(handle_, OnEos, this);
- esplusplayer_set_ready_to_prepare_cb(handle_, OnReadyToPrepare, this);
- esplusplayer_set_prepare_async_done_cb(handle_, OnPrepareDone, this);
- }
-\r
- static void DataFeedingTask(EsStreamReader* stream, esplusplayer_handle esplayer) {\r
- esplusplayer_es_packet pkt;\r
- while (true) {\r
- if (!stream->ReadNextPacket(pkt)) break;\r
- esplusplayer_submit_packet(esplayer, &pkt);\r
- delete pkt.buffer;\r
- }\r
- }\r
- static void OnError(const esplusplayer_error_type err_code, void* userdata) {
- std::cout << "OnError" << std::endl;
- }
- static void OnResourceConflicted(void* userdata) {
- std::cout << "OnResourceConflicted" << std::endl;
- }
- static void OnSeekDone(void* userdata) {
- std::cout << "OnSeekDone" << std::endl;
- }
- static void OnEos(void* userdata) {
- EsPlayerEventCallback* cb = static_cast<EsPlayerEventCallback*>(userdata);
- std::unique_lock<std::mutex> lk(cb->eos_m_);
- std::cout << "OnEos" << std::endl;
- cb->eos_ = true;
- lk.unlock();
- cb->eos_cv_.notify_all();
- }
- static void OnPrepareDone(bool ret, void* userdata) {
- EsPlayerEventCallback* cb = static_cast<EsPlayerEventCallback*>(userdata);
- std::unique_lock<std::mutex> lk(cb->prepare_done_m_);
- std::cout << "OnPrepareDone" << std::endl;
- cb->prepare_done_ = true;
- lk.unlock();
- cb->prepare_done_cv_.notify_all();
- }
- static void OnBufferStatus(const esplusplayer_stream_type type,
- const esplusplayer_buffer_status status,
- void* userdata) {
- auto buffer_status =
- status == ESPLUSPLAYER_BUFFER_STATUS_UNDERRUN ? "underrun" : "overrun";
- std::cout << "OnBufferStatus " << buffer_status << std::endl;
- }
- static void OnReadyToPrepare(const esplusplayer_stream_type type,
- void* userdata) {
- EsPlayerEventCallback* cb = static_cast<EsPlayerEventCallback*>(userdata);
- std::cout << "OnReadyToPrepare" << std::endl;
- std::unique_lock<std::mutex> lk(cb->data_m_);
- if (type == ESPLUSPLAYER_STREAM_TYPE_AUDIO) {
- cb->ready_audio_data_ = true;\r
- if (cb->audio_reader_ != nullptr) {\r
- cb->audio_feeding_task_ = std::thread(DataFeedingTask,\r
- std::ref(cb->audio_reader_),\r
- std::ref(cb->handle_));\r
- }\r
- std::cout << "Audio ready to prepare" << std::endl;
- } else if (type == ESPLUSPLAYER_STREAM_TYPE_VIDEO) {
- cb->ready_video_data_ = true;\r
- if (cb->video_reader_ != nullptr) {\r
- cb->video_feeding_task_ = std::thread(DataFeedingTask,\r
- std::ref(cb->video_reader_),\r
- std::ref(cb->handle_));\r
- }\r
- std::cout << "Video ready to prepare" << std::endl;
- }
- lk.unlock();
- cb->data_cv_.notify_all();
- }
- static void OnReadyToSeek(const esplusplayer_stream_type type,
- const uint64_t offset, void* userdata) {
- EsPlayerEventCallback* cb = static_cast<EsPlayerEventCallback*>(userdata);
- std::cout << "OnReadyToSeek" << std::endl;
- std::unique_lock<std::mutex> lk(cb->data_m_);
- if (type == ESPLUSPLAYER_STREAM_TYPE_AUDIO)
- cb->ready_audio_data_ = true;
- else if (type == ESPLUSPLAYER_STREAM_TYPE_VIDEO)
- cb->ready_video_data_ = true;
- lk.unlock();
- cb->data_cv_.notify_all();
- }
- void WaitAllStreamData() {
- std::unique_lock<std::mutex> lk(data_m_);
- std::cout << "WaitAllStreamData start" << std::endl;
- data_cv_.wait_for(lk, std::chrono::seconds(1), [this]() -> bool {
- return ready_audio_data_ && ready_video_data_;
- });\r
- std::cout << "WaitAllStreamData stop" << std::endl;
- lk.unlock();
- }
- void WaitAudioStreamData() {
- std::unique_lock<std::mutex> lk(data_m_);
- std::cout << "WaitAudioStreamData start" << std::endl;
- data_cv_.wait_for(lk, std::chrono::seconds(1),
- [this]() -> bool { return ready_audio_data_; });
- std::cout << "WaitAudioStreamData stop" << std::endl;
- lk.unlock();
- }
- void WaitVideoStreamData() {
- std::unique_lock<std::mutex> lk(data_m_);
- std::cout << "WaitVideoStreamData start" << std::endl;
- data_cv_.wait_for(lk, std::chrono::seconds(1),
- [this]() -> bool { return ready_audio_data_; });
- std::cout << "WaitVideoStreamData stop" << std::endl;
- lk.unlock();
- }
- void WaitForEos() {
- std::cout << "WaitForEos start" << std::endl;
- std::unique_lock<std::mutex> lk(eos_m_);
- eos_cv_.wait_for(lk, std::chrono::minutes(1),
- [this]() -> bool { return eos_; });\r
- std::cout << "WaitForEos stop" << std::endl;
- lk.unlock();
- }
- void WaitForPrepareDone() {
- std::cout << "WaitForPrepareDone start" << std::endl;
- std::unique_lock<std::mutex> lk(prepare_done_m_);
- prepare_done_cv_.wait_for(lk, std::chrono::seconds(10),\r
- [this]() -> bool { return prepare_done_; });\r
- std::cout << "WaitForPrepareDone stop" << std::endl;
- lk.unlock();
- }
-
- private:
- esplusplayer_handle handle_ = nullptr;\r
- EsStreamReader* video_reader_ = nullptr;\r
- EsStreamReader* audio_reader_ = nullptr;\r
- std::thread video_feeding_task_;\r
- std::thread audio_feeding_task_;\r
-\r
- bool eos_ = false;
- std::mutex eos_m_;
- std::condition_variable eos_cv_;
- bool ready_audio_data_ = false;
- bool ready_video_data_ = false;
- std::mutex data_m_;
- std::condition_variable data_cv_;
- bool prepare_done_ = false;
- std::mutex prepare_done_m_;
- std::condition_variable prepare_done_cv_;
-};\r
-\r
-#endif // __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_EVENT_LISTENER_H__
\ No newline at end of file
+++ /dev/null
-//\r
-// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
-//\r
-\r
-#ifndef __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_READER_H__\r
-#define __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_READER_H__\r
-\r
-\r
-#include <string>\r
-#include <fstream>\r
-\r
-#include "esplusplayer_capi/esplusplayer_capi.h"\r
-\r
-static const std::string tc_root_dir = "/tmp/esdata/";\r
-\r
-class EsStreamReader {\r
- public:\r
- explicit EsStreamReader(const std::string dirpath,\r
- esplusplayer_stream_type type) {\r
- dir_path_ = tc_root_dir + dirpath;\r
- es_data_file_ = dir_path_ + "ESP.es";\r
- es_info_file_ = dir_path_ + "ESP.info";\r
- extra_codec_file_ = dir_path_ + "ESP.codec_extradata";\r
- type_ = type;\r
- std::cout << "ES data file " << es_data_file_ << std::endl;\r
- }\r
- ~EsStreamReader() {\r
- if (stream_.is_open()) {\r
- stream_.close();\r
- }\r
- }\r
-\r
- bool SetStreamInfo(esplusplayer_handle& esplayer) {\r
- if (type_ == ESPLUSPLAYER_STREAM_TYPE_AUDIO) {\r
- esplusplayer_audio_stream_info audio_stream;\r
- audio_stream.codec_data = nullptr;\r
- audio_stream.codec_data_length = 0;\r
- GetExtraData_(audio_stream.codec_data, audio_stream.codec_data_length);\r
- if (!GetMediaInfo_(audio_stream)) {\r
- if (audio_stream.codec_data != nullptr)\r
- delete audio_stream.codec_data;\r
- return false;\r
- }\r
-\r
- esplusplayer_set_audio_stream_info(esplayer, &audio_stream);\r
- if (audio_stream.codec_data != nullptr)\r
- delete audio_stream.codec_data;\r
- } else if (type_ == ESPLUSPLAYER_STREAM_TYPE_VIDEO) {\r
- esplusplayer_video_stream_info video_stream;\r
- video_stream.codec_data = nullptr;\r
- video_stream.codec_data_length = 0;\r
- GetExtraData_(video_stream.codec_data, video_stream.codec_data_length);\r
- if (!GetMediaInfo_(video_stream)) {\r
- if (video_stream.codec_data != nullptr)\r
- delete video_stream.codec_data;\r
- return false;\r
- }\r
- esplusplayer_set_video_stream_info(esplayer, &video_stream);\r
- if (video_stream.codec_data != nullptr)\r
- delete video_stream.codec_data;\r
- }\r
- return true;\r
- }\r
-\r
- bool ReadNextPacket(esplusplayer_es_packet& pkt) {\r
- if (!stream_.is_open()) {\r
- stream_ = std::ifstream(es_data_file_, std::ifstream::binary);\r
- if (!stream_.is_open()) return false;\r
- }\r
- if (stream_.eof() || GetFileLeftSize_() < 24) {\r
- std::cout << type_ << " stream EOF" << std::endl;\r
- return false;\r
- }\r
- pkt.type = type_;\r
- std::uint64_t size;\r
- stream_.read(reinterpret_cast<char*>(&pkt.pts), sizeof(pkt.pts));\r
- pkt.pts = pkt.pts / 1000000; //ns -> ms\r
- stream_.read(reinterpret_cast<char*>(&pkt.duration), sizeof(pkt.duration));\r
- pkt.duration = pkt.duration / 1000000; //ns -> ms\r
- stream_.read(reinterpret_cast<char*>(&size), sizeof(size));\r
- pkt.buffer_size = static_cast<uint32_t>(size);\r
- if (pkt.buffer_size == 0) return false;\r
- pkt.buffer = new char[pkt.buffer_size];\r
- stream_.read(reinterpret_cast<char*>(pkt.buffer), pkt.buffer_size);\r
- pkt.matroska_color_info = nullptr;\r
- // std::cout << "Read audio/video buffer: " << type_ << std::endl;\r
- // std::cout << "Type: " << type_ << "Pts: " << pkt.pts << "duration: " <<\r
- // pkt.duration << "size: " << size << std::endl;\r
- return true;\r
- }\r
-\r
- void ResetReader() {\r
- stream_.seekg(0,std::ios::beg);\r
- }\r
-\r
-private:\r
- int GetFileLeftSize_(void) {\r
- if (!stream_.is_open()) return 0;\r
- int cur = stream_.tellg();\r
- stream_.seekg(0, stream_.end);\r
- int total = stream_.tellg();\r
- stream_.seekg(cur);\r
- return total - cur;\r
- }\r
- bool GetExtraData_(char*& data, unsigned int& size) {\r
- auto stream = std::ifstream(extra_codec_file_, std::ifstream::binary);\r
- if (!stream.is_open()) return false;\r
- stream.read(reinterpret_cast<char*>(&size), sizeof(size));\r
- if (size == 0) return false;\r
- data = new char[size];\r
- stream.read(data, size);\r
- stream.close();\r
- return true;\r
- }\r
-\r
- bool GetMediaInfo_(esplusplayer_video_stream_info& info) {\r
- auto stream = std::ifstream(es_info_file_, std::ifstream::in);\r
- if (!stream.is_open()) {\r
- std::cout << "No video es file: " << es_info_file_ << std::endl;\r
- return false;\r
- }\r
-\r
- uint32_t mime_type;\r
- stream >> mime_type >> info.width >> info.height >> info.max_width >> info.max_height >>\r
- info.framerate_num >> info.framerate_den;\r
- info.mime_type = static_cast<esplusplayer_video_mime_type>(mime_type);\r
- std::cout << "mime_type: " << info.mime_type << std::endl;\r
- std::cout << "info.width: " << info.width << std::endl;\r
- stream.close();\r
- return true;\r
- }\r
-\r
- bool GetMediaInfo_(esplusplayer_audio_stream_info& info) {\r
- auto stream = std::ifstream(es_info_file_, std::ifstream::in);\r
- if (!stream.is_open()) {\r
- std::cout << "No audio es file: " << es_info_file_ << std::endl;\r
- return false;\r
- }\r
- uint32_t mime_type;\r
- stream >> mime_type >> info.sample_rate >> info.channels;\r
- info.mime_type = static_cast<esplusplayer_audio_mime_type>(mime_type);\r
- std::cout << "mime_type: " << info.mime_type << std::endl;\r
- std::cout << "info.sample_rate: " << info.sample_rate << std::endl;\r
- stream.close();\r
- return true;\r
- }\r
-\r
-\r
-\r
- private:\r
- std::string dir_path_;\r
- std::string es_data_file_;\r
- std::string es_info_file_;\r
- std::string extra_codec_file_;\r
- std::ifstream stream_;\r
- esplusplayer_stream_type type_;\r
-};\r
-\r
-#endif // __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_READER_H__
\ No newline at end of file
+++ /dev/null
-//
-// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#ifndef __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_TCLIST_H__
-#define __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_TCLIST_H__
-
-#include <map>
-#include <string>
-#include <tuple>
-#include <vector>
-#include <assert.h>
-
-namespace tc
-{
- enum class tc_type {
- kDefault,
- kCosmos,
- };
-
- enum class stream_state_type {
- kNormal,
- k4k,
- k8k,
- kVideoOnly,
- kAudioOnly,
- kNotSupportStream,
- k360,
- kNonSeekable,
- kDualmono,
- kNoIFrameListInHls,
- // add more state
- kSize,
- };
-
- enum class contents_type {
- kDash,
- kHls,
- kHttp,
- kSize
- };
-
- enum class container_type {
- kMp4,
- kMp3,
- kOgg,
- kAvi,
- kWebM,
- kAsf,
- kWmv,
- kWma,
- kMkv,
- kMka,
- kMk3d,
- kMkms,
- kTs,
- kDivx,
- kEs,
- kMov,
- // more container
- kSize
- };
-
- enum class drm_type {
- kClean,
- kPlayready,
- kVerimatrix,
- kWidevineModular,
- // more drm type
- kSize
- };
-
- enum class video_codec_type {
- kNone,
- kH261,
- kH262,
- kH263,
- kH264, // avc
- kH265,
- kHevc,
- kVc1,
- kVp9,
- kMp4_Visual,
- kMpeg1,
- kMpeg2,
- // more codec type
- kSize
- };
-
- enum class audio_codec_type {
- kNone,
- kMp3,
- kAc3,
- kAac,
- kE_ac3,
- kWma,
- // more codec type
- kSize
- };
-
- enum class audio_track_type {
- kSingle,
- kMulti,
- kSize
- };
-
- using url = std::string;
- using contents_tag = std::tuple<stream_state_type, contents_type, container_type, drm_type, video_codec_type, audio_codec_type, audio_track_type, unsigned int>;
- using tc_map = std::map<url, contents_tag>;
- using tc_list = std::vector<url>;
-
- class TCList {
- public:
- static TCList& Instance();
- static void InitializeTC(tc_type type);
-
- static void Kill();
-
- tc_map GetTCMap() const;
- tc_list GetTCURIList() const;
-
- // return uri tag from args
- static inline contents_tag MakeContentsTag(stream_state_type t0, contents_type t1, container_type t2, drm_type t3, video_codec_type t4, audio_codec_type t5, audio_track_type t6) {
- return std::make_tuple(t0, t1, t2, t3, t4, t5, t6, 0);
- }
-
- static inline contents_tag MakeUniqueContentsTag(stream_state_type t0, contents_type t1, container_type t2, drm_type t3, video_codec_type t4, audio_codec_type t5, audio_track_type t6, unsigned int unique_id) {
- assert(unique_id != 0); // because 0 is default id for MakeContentTag()
- return std::make_tuple(t0, t1, t2, t3, t4, t5, t6, unique_id);
- }
-
- static inline stream_state_type GetStreamStateType(contents_tag tag) { return std::get<0>(tag); }
- static inline contents_type GetContentsType(contents_tag tag) { return std::get<1>(tag); }
- static inline container_type GetContainerType(contents_tag tag) { return std::get<2>(tag); }
- static inline drm_type GetDrmType(contents_tag tag) { return std::get<3>(tag); }
- static inline video_codec_type GetVideoCodecType(contents_tag tag) { return std::get<4>(tag); }
- static inline audio_codec_type GetAudioCodecType(contents_tag tag) { return std::get<5>(tag); }
- static inline audio_track_type GetAudioTrackType(contents_tag tag) { return std::get<6>(tag); }
-
- virtual ~TCList();
- private:
- TCList(tc_type type);
-
-#ifdef VD_UNIT_TEST
- void MountCIFS();
- void UnmountCIFS();
-#endif
-
- private:
- tc_type type_;
- tc_map map_;
- tc_list list_;
- };
-
- namespace hls_tc {
- static const url hls_normal_clean_1 = "";
- static const url hls_normal_clean_2 = "";
- static const url hls_normal_clean_3 = "";
-
- static const url hls_normal_clean_multiaudio_subtitle_1 = "";
- static const url hls_normal_clean_discontinuity_1 = "";
- }
-
- namespace hls_abnormal_tc {
-
- }
-
- namespace dash_tc {
- static const url dash_normal_clean_1 = "";
- static const url dash_normal_clean_2 = "";
- static const url dash_normal_clean_3 = "";
-
- static const url dash_normal_clean_uhd_1 = "";
- static const url dash_normal_clean_uhd_2 = "";
-
- }
-
- namespace http_tc {
- static const url avc_aac_mp4 = "";
- static const url avc_mp3_mp4 = "";
- static const url hevc_aac_4k_mp4 = "";
- static const url avc_aac_4k_mp4 = "";
- static const url hevc_aac_4k_ts = "";
-
- static const url aac_audioonly_es = "";
- static const url avc_videoonly_es = "";
-
- static const url avc_aac_360_mp4 = "";
- static const url hevc_aac_360_mp4 = "";
- static const url avc_aac_360_4k_mp4 = "";
-
- static const url mp3_mp3 = "";
-
- static const url mpeg2video_ac3_ac3_tp = "";
- }
-
- namespace track_tc {
- static const url http_1video_2audio = http_tc::mpeg2video_ac3_ac3_tp;
- static const url hls_1video_2audio_4text = "";
- static const url hls_1video_2audio_3text = hls_tc::hls_normal_clean_multiaudio_subtitle_1;
- static const url hls_1video_1audio_0text = hls_tc::hls_normal_clean_3;
- static const url dash_2video_1audio_0text = "";
- static const url dash_2video_2audio_0text = "";
- static const url dash_1video_1audio_0text = dash_tc::dash_normal_clean_3;
- static const url dash_1video_0audio_0text = "";
- static const url dash_1video_1audio_2text_ttml = "";
- static const url dash_1video_1audio_2text_xml = "";
- }
-}
-
-#endif // __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_TCLIST_H__
\ No newline at end of file
+++ /dev/null
-//
-// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
-//
-#ifndef __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_UTILITY_H__
-#define __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_UTILITY_H__
-
-#include <Ecore_Evas.h>
-
-#include "core/utils/plusplayer_log.h"
-#include "plusplayer/plusplayer.h"
-#include "ut/include/appwindow.h"
-
-namespace utils {
-class Utility;
-using evas_h = Evas_Object*;
-
-class Utility {
- public:
- static Utility& Instance();
- static void ThreadSleep(long ms);
- static void Kill();
- virtual ~Utility();
-
- const char* GetCurrentTestName(void);
-
- plusplayer::PlusPlayer::Ptr GetCreatedPlusPlayer(std::string& uri);
-
- plusplayer::PlusPlayer::Ptr GetPreparedPlusPlayer(std::string& uri);
-
- void DestroyPlayer(plusplayer::PlusPlayer::Ptr& player);
-
- bool IsPaused(plusplayer::PlusPlayer::Ptr& player, int monitoring_time_msec);
-
- evas_h GetWindow() const;
-
- Utility(const Utility& rhs) = delete;
- Utility& operator=(const Utility& rhs) = delete;
-
- private:
- explicit Utility();
-
- private:
- std::unique_ptr<plusplayer_ut::AppWindow> appwindow_;
-};
-
-} // namespace utils
-
-#endif // __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_UTILITY_H__
\ No newline at end of file
+++ /dev/null
-//\r
-// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
-//\r
-\r
-#ifndef __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ESCOMMON_H__\r
-#define __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ESCOMMON_H__\r
-\r
-#include <chrono>\r
-#include <cstdlib>\r
-#include <fstream>\r
-#include <memory>\r
-#include <string>\r
-#include <thread>\r
-#include <vector>\r
-\r
-#include "gtest/gtest.h"\r
-\r
-#include "plusplayer/espacket.h"\r
-#include "trackrenderer/core/decoderinputbuffer.h"\r
-#include "ut/include/appwindow.h"\r
-\r
-namespace pp = plusplayer;\r
-\r
-namespace utils {\r
-inline bool Exists(const std::string &path) {\r
- std::ifstream ifile(path);\r
- return static_cast<bool>(ifile);\r
-}\r
-} // namespace utils\r
-\r
-namespace {\r
-class Environment {\r
- public:\r
- Environment() {\r
- appwindow_.reset(new plusplayer_ut::AppWindow(0, 0, 1920, 1080));\r
- }\r
- void *Window() { return appwindow_->GetWindow().obj; }\r
- void *EcoreWindow() { return appwindow_->GetEcoreWL2Window(); }\r
-\r
- private:\r
- std::shared_ptr<plusplayer_ut::AppWindow> appwindow_;\r
-};\r
-\r
-class ESPacketDownloader {\r
- public:\r
- static void Init() {\r
- if (utils::Exists("/tmp/esdata")) {\r
- return;\r
- }\r
- std::cout << "Download ESData via http - path : /tmp/esdata" << std::endl;\r
- int ret = std::system(\r
- "/usr/bin/wget "\r
- "--recursive --directory-prefix=/tmp/esdata --force-directories "\r
- "--no-host-directories --cut-dirs=2 --no-parent --reject=index.html "\r
- "");\r
- assert(ret == 0 && "wget is failed, please retry");\r
- }\r
-};\r
-} // namespace\r
-\r
-namespace es {\r
-inline std::uint64_t ConvertNsToMs(std::uint64_t ms) {\r
- constexpr std::uint64_t ns_unit = 1000000;\r
- return ms / ns_unit;\r
-}\r
-struct Packet {\r
- std::uint64_t pts;\r
- std::uint64_t duration;\r
- std::uint64_t size;\r
- std::shared_ptr<char> data;\r
-\r
- pp::trackrenderer::DecoderInputBufferPtr MakeDecoderInputBuffer(\r
- pp::trackrenderer::TrackType type) {\r
- GstMapInfo map;\r
- auto gstbuffer = gst_buffer_new_and_alloc(size);\r
- gst_buffer_map(gstbuffer, &map, GST_MAP_WRITE);\r
- memcpy(map.data, data.get(), size);\r
- gst_buffer_unmap(gstbuffer, &map);\r
- GST_BUFFER_PTS(gstbuffer) = pts;\r
- GST_BUFFER_DURATION(gstbuffer) = duration;\r
- auto buffer =\r
- pp::trackrenderer::DecoderInputBuffer::Create(type, 0, gstbuffer);\r
- gst_buffer_unref(gstbuffer);\r
- return std::move(buffer);\r
- }\r
-\r
- static pp::trackrenderer::DecoderInputBufferPtr MakeEosBuffer(\r
- pp::trackrenderer::TrackType type) {\r
- return std::move(pp::trackrenderer::DecoderInputBuffer::Create(type));\r
- }\r
-\r
- pp::EsPacketPtr MakeEsPacket(pp::StreamType type) {\r
- return std::move(\r
- pp::EsPacket::Create(type, data, static_cast<std::uint32_t>(size),\r
- // pts/1000000,duration/1000000));\r
- ConvertNsToMs(pts), ConvertNsToMs(duration)));\r
- }\r
-\r
- static pp::EsPacketPtr MakeEosPacket(pp::StreamType type) {\r
- return std::move(pp::EsPacket::CreateEos(type));\r
- }\r
-};\r
-\r
-struct CodecExtraData {\r
- std::uint32_t size;\r
- std::shared_ptr<char> data;\r
-};\r
-using PacketPtr = std::shared_ptr<Packet>;\r
-using CodecExtraDataPtr = std::shared_ptr<CodecExtraData>;\r
-\r
-template <typename TRACK, typename TRACKTYPE>\r
-struct VideoInfo {\r
- std::string mimetype;\r
- int width, height;\r
- int maxwidth, maxheight;\r
- int framerate_num, framerate_den;\r
-\r
- void ExtractMediaInfoFrom(std::ifstream &stream) {\r
- stream >> mimetype >> width >> height >> maxwidth >> maxheight >>\r
- framerate_num >> framerate_den;\r
- }\r
-\r
- TRACK GetTrack() {\r
- TRACK t;\r
- t.active = true;\r
- t.index = 0;\r
- t.type = TRACKTYPE::kTrackTypeVideo;\r
- t.mimetype = mimetype;\r
- t.width = width;\r
- t.height = height;\r
- t.maxwidth = maxwidth;\r
- t.maxheight = maxheight;\r
- t.framerate_num = framerate_num;\r
- t.framerate_den = framerate_den;\r
- return t;\r
- }\r
-};\r
-\r
-template <typename TRACK, typename TRACKTYPE>\r
-struct AudioInfo {\r
- std::string mimetype;\r
- int samplerate;\r
- int channels;\r
- int version;\r
-\r
- void ExtractMediaInfoFrom(std::ifstream &stream) {\r
- stream >> mimetype >> samplerate >> channels >> version;\r
- }\r
- TRACK GetTrack() {\r
- TRACK t;\r
- t.active = true;\r
- t.index = 0;\r
- t.type = TRACKTYPE::kTrackTypeAudio;\r
- t.mimetype = mimetype;\r
- t.sample_rate = samplerate;\r
- t.channels = channels;\r
- t.version = version;\r
- return t;\r
- }\r
-};\r
-\r
-template <typename TRACKTYPE>\r
-class StreamReader {\r
- public:\r
- using Ptr = std::shared_ptr<StreamReader<TRACKTYPE>>;\r
- friend Ptr;\r
- static Ptr Create(const std::string &dirpath, const TRACKTYPE &type) {\r
- return Ptr(new StreamReader(dirpath, type));\r
- }\r
- virtual ~StreamReader() {\r
- if (stream_.is_open()) {\r
- stream_.close();\r
- }\r
- }\r
-\r
- private:\r
- explicit StreamReader(const std::string dirpath, const TRACKTYPE &type)\r
- : type_(type) {\r
- dirpath_ = "/tmp/esdata/" + dirpath;\r
- if (utils::Exists(dirpath_) == false) {\r
- throw std::runtime_error(dirpath_ + "doesn't exist");\r
- }\r
- stream_ = std::ifstream(dirpath_ + "/ESP.es", std::ifstream::binary);\r
- }\r
-\r
- public:\r
- CodecExtraDataPtr GetExtraData() {\r
- std::string path = dirpath_ + "/ESP.codec_extradata";\r
- auto stream = std::ifstream(path, std::ifstream::binary);\r
- auto extradata = CodecExtraDataPtr(new CodecExtraData);\r
- stream.read(reinterpret_cast<char *>(&extradata->size),\r
- sizeof extradata->size);\r
- using DataPtr = std::shared_ptr<char>;\r
- extradata->data = DataPtr(new char[extradata->size]);\r
- stream.read(reinterpret_cast<char *>(extradata->data.get()),\r
- extradata->size);\r
- stream.close();\r
- return extradata;\r
- }\r
-\r
- PacketPtr ReadNextPacket() {\r
- if (stream_.eof()) {\r
- return nullptr;\r
- }\r
- auto pkt = PacketPtr(new Packet);\r
- stream_.read(reinterpret_cast<char *>(&pkt->pts), sizeof pkt->pts);\r
- stream_.read(reinterpret_cast<char *>(&pkt->duration),\r
- sizeof pkt->duration);\r
- stream_.read(reinterpret_cast<char *>(&pkt->size), sizeof pkt->size);\r
- using DataPtr = std::unique_ptr<char>;\r
- pkt->data = DataPtr(new char[pkt->size]);\r
- stream_.read(reinterpret_cast<char *>(pkt->data.get()), pkt->size);\r
- return pkt;\r
- }\r
-\r
- template <typename T>\r
- T GetMediaInfo() {\r
- std::string path = dirpath_ + "/ESP.info";\r
- T media;\r
- auto stream = std::ifstream(path, std::ifstream::in);\r
- media.ExtractMediaInfoFrom(stream);\r
- stream.close();\r
- return media;\r
- }\r
-\r
- TRACKTYPE GetTrackType() { return type_; }\r
-\r
- private:\r
- std::string dirpath_;\r
- std::ifstream stream_;\r
- TRACKTYPE type_;\r
-};\r
-\r
-} // namespace es\r
-#endif // __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ESCOMMON_H__
\ No newline at end of file
+++ /dev/null
-//
-// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
-//
-#include "ut/include/plusplayer/tclist.h"
-
-#include <sys/mount.h>
-#include <cassert>
-#include <chrono>
-#include <initializer_list>
-#include <memory>
-
-
-using tclist_ptr = std::unique_ptr<TCList>;
-static tclist_ptr ptr = nullptr;
-
-TCList& TCList::Instance() { return *(ptr.get()); }
-
-void TCList::InitializeTC(tc_type type) {
- if (ptr.get() == nullptr) ptr.reset(new TCList(type));
-}
-
-void TCList::Kill() { ptr.reset(); }
-
-tc_map TCList::GetTCMap() const { return this->map_; }
-
-tc_list TCList::GetTCURIList() const {
- std::vector<url> l;
- for (const auto& p : this->map_) {
- l.emplace_back(p.first);
- }
- return l;
-}
-
-TCList::TCList(tc_type type) : type_(type) {
- this->map_.insert(http_tc::tc_map_.begin(), http_tc::tc_map_.end());
- this->map_.insert(hls_tc::tc_map_.begin(), hls_tc::tc_map_.end());
- this->map_.insert(dash_tc::tc_map_.begin(), dash_tc::tc_map_.end());
-#ifdef VD_UNIT_TEST
- this->MountCIFS();
-#endif
-}
-
-TCList::~TCList() {
-#ifdef VD_UNIT_TEST
- this->UnmountCIFS();
-#endif
-}
-
-#ifdef VD_UNIT_TEST
-void TCList::MountCIFS() {
- LOG_DEBUG("system result : %d",
- system("/usr/bin/chmod +x /usr/bin/mount-server.sh"));
- LOG_DEBUG("system result : %d", system("/usr/bin/mount-server.sh"));
-}
-
-void TCList::UnmountCIFS() {
- LOG_DEBUG(
- "system result : %d",
- system("/usr/bin/umount -f -l -a -t cifs")); // -l : lazy umount for
- // mount to windows
-}
-#endif
-} // namespace tc
+++ /dev/null
-//
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "ut/include/plusplayer/tclist.h"
-
-using tc::tc_type;
-using tc::TCList;
-
-int main(int argc, char *argv[]) {
- //TCList::InitializeTC(tc_type::kDefault);
-
- ::testing::InitGoogleTest(&argc, argv);
- ::testing::InitGoogleMock(&argc, argv);
-
- auto ret = -1;
- ret = RUN_ALL_TESTS();
-
- //TCList::Kill();
-
- return ret;
-}
+++ /dev/null
-//
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#include <chrono> // std::chrono::seconds()
-#include <iostream>
-#include <memory>
-#include <string>
-#include <thread> // std::thread
-
-#include "gst/gst.h"
-#include "gtest/gtest.h"
-
-#include "core/track_util.h"
-#include "player/defaultplayer.h"
-#include "plusplayer/plusplayer.h"
-#include "plusplayer/track.h"
-#include "trackrenderer/display.h"
-#include "trackrenderer/trackrenderer.h"
-#include "tracksource/tracksource.h"
-#include "ut/include/appwindow.h"
-
-class TrackRendererTest : public ::testing::Test {
- public:
- TrackRendererTest() {}
-
- void SetUp() override {
- gst_init_check(nullptr, nullptr, nullptr);
-
- // basic , clean stream
- std::string url = "";
-
- // multi-track with closed caption data
- // std::string url =
- // "http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8";
-
- // single-track with closed caption data
- // std::string url =
- // "http://mediadelivery.mlbcontrol.net/2015/hls_testbeds/ads_302/master_wired_fwv2.m3u8";
- TypeFinder typefinder(url);
- typefinder.Probe();
- StreamingProperty property;
- tracksource_ = TrackSource::CreateCompositor();
- tracksource_->AddSource(&typefinder, property);
- ASSERT_TRUE(tracksource_.get());
-
- trackrenderer_ = TrackRenderer::Create();
- ASSERT_TRUE(trackrenderer_.get());
-
- appwindow_.reset(new plusplayer_ut::AppWindow(0, 0, 1920, 1080));
- ASSERT_TRUE(appwindow_.get());
-
- trackrenderer_->SetDisplayMode(plusplayer::DisplayMode::kDstRoi);
- trackrenderer_->SetDisplay(plusplayer::DisplayType::kOverlay,
- appwindow_->GetWindow().obj);
- plusplayer::Geometry roi;
- roi.x = 600, roi.y = 300, roi.w = 720, roi.h = 480;
- trackrenderer_->SetDisplayRoi(roi);
- }
-
- void TearDown() override {
- trackrenderer_->Stop();
- tracksource_->Stop();
- }
-
- std::shared_ptr<TrackSource> GetTrackSource() { return tracksource_; }
- std::shared_ptr<TrackRenderer> GetTrackRenderer() { return trackrenderer_; }
-
- private:
- std::shared_ptr<TrackSource> tracksource_;
- std::shared_ptr<TrackRenderer> trackrenderer_;
- std::unique_ptr<plusplayer_ut::AppWindow> appwindow_;
-};
-
-Track SetVideoInfo(std::string mimetype, int w, int h, int framerate_num,
- int framerate_den) {
- Track trackinfo;
- trackinfo.mimetype = mimetype;
- trackinfo.width = w;
- trackinfo.height = h;
- trackinfo.framerate_num = framerate_num;
- trackinfo.framerate_den = framerate_den;
- trackinfo.active = true;
-
- return trackinfo;
-}
-
-Track SetAudioInfo(std::string mimetype, int samplerate, int sampleformat,
- int channels, int version) {
- Track trackinfo;
- trackinfo.mimetype = mimetype;
- trackinfo.sample_rate = samplerate;
- trackinfo.sample_format = sampleformat;
- trackinfo.channels = channels;
- trackinfo.version = version;
- trackinfo.active = true;
- return trackinfo;
-}
-
-TEST_F(TrackRendererTest, DISABLED_Create) {}
-
-TEST_F(TrackRendererTest, DISABLED_Prepare) { // 기존 Prepare와 합쳐도 됨
- auto tracksource = GetTrackSource();
- auto trackrenderer = GetTrackRenderer();
-
- tracksource->Prepare(); // READY to PAUSE
- std::vector<Track> track = tracksource->GetTrackInfo();
-
- // for ut test. will be remove is after tracksource implement GetTrackInfo().
- Track trackvideoinfo = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
- Track trackaudioinfo = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
- std::vector<Track> track_vector = {trackvideoinfo, trackaudioinfo};
- bool ret =
- trackrenderer->SetTrack(track_vector); // in PlusPlayer or in Wrapper
- ASSERT_TRUE(ret);
- // for ut test. will be remove is after tracksource implement GetTrackInfo()
- // end
-
- trackrenderer->Prepare(); // NULL to READY
-}
-
-TEST_F(TrackRendererTest, DISABLED_CreateAndSetWindow) {
- auto tracksource = GetTrackSource();
- auto trackrenderer = GetTrackRenderer();
-}
-
-TEST_F(TrackRendererTest, DISABLED_Start) {
- auto tracksource = GetTrackSource();
- auto trackrenderer = GetTrackRenderer();
-
- tracksource->Prepare(); // READY to PAUSE , track parsing done
-
- std::vector<Track> track = tracksource->GetTrackInfo();
-
- // for ut test. will be remove is after tracksource implement GetTrackInfo().
- Track vtrack = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
- Track atrack = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
- std::vector<Track> selectedtrack = {vtrack, atrack};
- bool ret = trackrenderer->SetTrack(selectedtrack);
-
- track_util::ShowTrackInfo(selectedtrack);
- ASSERT_TRUE(ret);
- // for ut test. will be remove is after tracksource implement GetTrackInfo()
- // end
-
- trackrenderer->Prepare(); // NULL to READY
-
- trackrenderer->Start(); // READY to PAUSE to PLAYING
- // PAUSE to PLAYING , Hands-off -> Listener -> SubmitPacket
- tracksource->Start();
-
- std::this_thread::sleep_for(std::chrono::seconds(60));
- std::cout << "wait for 10 secs done ... terminate the test" << std::endl;
-}
-
-TEST_F(TrackRendererTest, DISABLED_SetTrack) {
- auto tracksource = GetTrackSource();
- auto trackrenderer = GetTrackRenderer();
-
- Track trackvideoinfo = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
- Track trackaudioinfo = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
- std::vector<Track> track_vector = {trackvideoinfo, trackaudioinfo};
- bool ret = trackrenderer->SetTrack(track_vector);
- ASSERT_TRUE(ret);
-}
-
-TEST_F(TrackRendererTest, DISABLED_ChangeTrack) {
-}
+++ /dev/null
-//
-// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
-//
-
-#include <boost/scope_exit.hpp>
-#include <chrono> // std::chrono::seconds()
-#include <iostream>
-#include <memory>
-#include <queue>
-#include <string>
-#include <thread> // std::thread
-
-#include "gst/gst.h"
-#include "gtest/gtest.h"
-
-#include "libavformat/avformat.h"
-#include "plusplayer/track.h"
-#include "trackrenderer/core/utils/log.h"
-#include "trackrenderer/display.h"
-#include "trackrenderer/trackrenderer.h"
-#include "tracksource/tracksource.h"
-
-using namespace plusplayer;
-using namespace plusplayer::trackrenderer;
-
-namespace {
-
-class ExternalDemuxer {
- public:
- explicit ExternalDemuxer(const std::string& url) : url_(url) {
-// Init_();
- }
-
- private:
- struct Context {
- bool stop = false;
- std::shared_ptr<TrackRenderer> trackrenderer;
- };
-
- bool Init_() {
- int ret = 0;
- av_register_all();
- if(av_open_input_file(&ic_, url_.c_str() , nullptr , 0 , nullptr) < 0) {
- return false;
- }
- ret = av_find_stream_info(ic_);
- BOOST_SCOPE_EXIT(&ic_, &ret) {
- if (ic_ && ret < 0) {
- av_close_input_file(ic_);
- }
- } BOOST_SCOPE_EXIT_END;
-
- if (ret < 0) {
- return false;
- }
-
- ret = av_find_stream_info(ic_);
- if(ret < 0) {
- return false;
- }
- return true;
- }
-
- void InputTask_(Context* ctx) {
- while (!ctx->stop) {
- int ret = 0;
- AVPacket packet;
- av_init_packet(&packet);
- if(ctx->stop) break;
- ret = av_read_frame(ic_, &packet);
- if(ret < 0) {
- TRACKRENDERER_ERROR("av_read_frame error!!");
- break;
- }
- MakeGstBuffer_(&packet);
- }
- }
- plusplayer::DecoderInputBuffer* MakeGstBuffer_(AVPacket *packet) {
- return nullptr;
- }
- private:
- std::string url_;
- AVFormatContext* ic_ = nullptr;
- Context ctx;
-};
-#if 0
- void DecoderInputTask(DataCtx* ctx) {
- while (!ctx->stop) {
- char* buf = read_es(frame_cnt, ctx->type, &size);
- push_media_data(buf, size, pts, ctx->appsrc, send_segment);
- }
- private:
-
-#endif
-} // end unname space
-
-class TrackRendererTest : public ::testing::Test {
- public:
- TrackRendererTest() {}
-
- void SetUp() override {
-
- appwindow_.reset(new AppWindow(0, 0, 1920, 1080));
- ASSERT_TRUE(appwindow_.get());
-
- //basic , clean stream
- std::string url = "/opt/media/USBDriveA1/test.mp4";
- ::ExternalDemuxer external_demuxer(url);
-
- // multi-track with closed caption data
- // std::string url =
- // "http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8";
-
- // single-track with closed caption data
- // std::string url =
- // "http://mediadelivery.mlbcontrol.net/2015/hls_testbeds/ads_302/master_wired_fwv2.m3u8";
- trackrenderer_ = TrackRenderer::Create();
- ASSERT_TRUE(trackrenderer_.get());
-
- trackrenderer_->SetDisplayMode(DisplayMode::kDstRoi);
- trackrenderer_->SetDisplay(DisplayType::kOverlay,appwindow_->GetWindow().obj);
- Geometry roi;
- roi.x = 600, roi.y = 300, roi.w = 720, roi.h = 480;
- trackrenderer_->SetDisplayRoi(roi);
- }
-
- void TearDown() override {
- trackrenderer_->Stop();
- }
-
- std::shared_ptr<TrackRenderer> GetTrackRenderer() { return trackrenderer_; }
- SourceType& GetSourceType() const { return type_; }
-
- private:
- SourceType type_;
- std::shared_ptr<TrackRenderer> trackrenderer_;
- std::unique_ptr<AppWindow> appwindow_;
-};
-
-
-Track SetVideoInfo(std::string mimetype, int w, int h, int framerate_num, int framerate_den) {
- Track trackinfo;
- trackinfo.mimetype = mimetype;
- trackinfo.width = w;
- trackinfo.height = h;
- trackinfo.framerate_num = framerate_num;
- trackinfo.framerate_den = framerate_den;
- trackinfo.active = true;
-
- return trackinfo;
-}
-
-Track SetAudioInfo(std::string mimetype, int samplerate, int sampleformat, int channels, int version) {
- Track trackinfo;
- trackinfo.mimetype = mimetype;
- trackinfo.sample_rate = samplerate;
- trackinfo.sample_format = sampleformat;
- trackinfo.channels = channels;
- trackinfo.version = version;
- trackinfo.active = true;
- return trackinfo;
-}
-
-TEST_F(TrackRendererTest, DISABLED_Create) {}
-
-TEST_F(TrackRendererTest, DISABLED_Prepare) {
- auto trackrenderer = GetTrackRenderer();
-
- Track trackvideoinfo = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
- Track trackaudioinfo = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
- std::vector<Track> track_vector = {trackvideoinfo, trackaudioinfo};
- bool ret = trackrenderer->SetTrack(track_vector); // in PlusPlayer or in Wrapper
- ASSERT_TRUE(ret);
- trackrenderer->Prepare(); // NULL to READY
-}
-
-TEST_F(TrackRendererTest, DISABLED_SetDisplay) {
-}
-
-TEST_F(TrackRendererTest, DISABLED_Start) {
- auto trackrenderer = GetTrackRenderer();
- auto start = logutil::performance::Start();
-
- Track vtrack = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
- Track atrack = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
- std::vector<Track> selectedtrack = {vtrack, atrack};
- bool ret = trackrenderer->SetTrack(selectedtrack);
- track_util::ShowTrackInfo(selectedtrack);
- ASSERT_TRUE(ret);
-
- trackrenderer->Prepare(); // NULL to READY
-
- trackrenderer->Start(); // READY to PAUSE to PLAYING
- // PAUSE to PLAYING , Hands-off -> Listener -> SubmitPacket
- logutil::performance::End(start, "[TrackRenderer start::]");
- std::this_thread::sleep_for(std::chrono::seconds(60));
- std::cout << "wait for 10 secs done ... terminate the test" << std::endl;
-}
-
-TEST_F(TrackRendererTest, DISABLED_SetTrack) {
- auto trackrenderer = GetTrackRenderer();
-
- Track trackvideoinfo = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
- Track trackaudioinfo = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
- std::vector<Track> track_vector = {trackvideoinfo, trackaudioinfo};
- bool ret = trackrenderer->SetTrack(track_vector);
- ASSERT_TRUE(ret);
-}
-
-TEST_F(TrackRendererTest, DISABLED_ChangeTrack) {
- auto trackrenderer = GetTrackRenderer();
- Track trackvideoinfo = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
- Track trackaudioinfo = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
- std::vector<Track> track_vector = {trackvideoinfo, trackaudioinfo};
- bool ret = trackrenderer->SetTrack(track_vector); // in PlusPlayer or in Wrapper
- ASSERT_TRUE(ret);
-
- trackrenderer->Prepare(); // NULL to READY
-
- start = logutil::performance::Start();
- trackrenderer->Start(); // READY to PAUSE to PLAYING
-
- logutil::performance::End(start, "player start");
- std::this_thread::sleep_for(std::chrono::seconds(5));
-
- TRACKRENDERER_DEBUG("Start Track change");
- Track changed_info;
- changed_info.channels = 2;
- changed_info.mimetype = "audio/mpeg";
- changed_info.sample_rate = 48000;
- changed_info.sample_format = 2;
- changed_info.version = 4;
- changed_info.active = true;
-
- // push thread for appsrc must be stopped first. otherwisw appsrc block mode
- // makes deadlock
- trackrenderer->ChangeTrack(changed_info);
- TRACKRENDERER_DEBUG("ChangeTrack DONE");
- std::this_thread::sleep_for(std::chrono::seconds(15));
- TRACKRENDERER_DEBUG("STOP");
-}
+++ /dev/null
-/**
-* Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
-* PROPRIETARY/CONFIDENTIAL
-* This software is the confidential and proprietary
-* information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
-* not disclose such Confidential Information and shall use it only in
-* accordance with the terms of the license agreement you entered into with
-* SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
-* suitability of the software, either express or implied, including but not
-* limited to the implied warranties of merchantability, fitness for a
-* particular purpose, or non-infringement. SAMSUNG shall not be liable for any
-* damages suffered by licensee as a result of using, modifying or distributing
-* this software or its derivatives.
-*/
-#include "gst/gst.h"
-#include "gtest/gtest.h"
-
-#include "trackrenderer/core/utils/log.h"
-#include "trackrenderer/version.h"
-#include "trackrenderer_capi/trackrenderer_capi.h"
-
-TEST(TrackRendererCapiTest, DISABLED_get_version) {
- std::string version { TRACKRENDERER_STRINGIFY(LIB_TRACKRENDERER_VERSION)};
- TRACKRENDERER_INFO("version string[%s]", trackrenderer_get_version());
- ASSERT_STREQ(version.c_str() , trackrenderer_get_version());
-}
-
-TEST(TrackRendererCapiTest, DISABLED_get_version_int) {
- uint32_t version = LIB_TRACKRENDERER_VERSION_INT;
- TRACKRENDERER_INFO("version int[%u]", trackrenderer_get_version_int());
- ASSERT_EQ(version , trackrenderer_get_version_int());
-}