/* * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of Code Aurora Forum, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef OVERLAY_STATE_H #define OVERLAY_STATE_H #include "overlayUtils.h" #include "overlayImpl.h" #include "overlayRotator.h" #include "pipes/overlayGenPipe.h" #include "pipes/overlayVideoExtPipe.h" #include "pipes/overlayUIMirrorPipe.h" #include "pipes/overlay3DPipe.h" namespace overlay { /* * Used by Overlay class. Invokes each event * */ class OverlayState : utils::NoCopy { public: /*ctor*/ explicit OverlayState(); /*dtor*/ ~OverlayState(); /* return current state */ utils::eOverlayState state() const; /* Hard reset to a new state. If the state is the same * as the current one, it would be a no-op */ OverlayImplBase* reset(utils::eOverlayState s); /* Caller pass the state to the handleEvent function. * The input is the current OverlayImplBase*, and output is * a pointer to (possibly new) instance of OverlayImplBase * The eFormat can be 2D/3D etc. */ OverlayImplBase* handleEvent(utils::eOverlayState s, OverlayImplBase* ov); /* Dump */ void dump() const; private: /* Transitions from a state to a state. Default behavior is to move from an * old state to CLOSED and from CLOSED to a new state. Any impl wishing to * copy pipes should specialize this call */ template OverlayImplBase* handle_from_to(OverlayImplBase* ov); /* Just a convenient intermediate function to bring down the number of * combinations arising from multiple states */ template OverlayImplBase* handle_from(utils::eOverlayState toState, OverlayImplBase* ov); /* Substitues for partially specialized templated handle functions since the * standard doesn't allow partial specialization of functions */ template OverlayImplBase* handle_xxx_to_CLOSED(OverlayImplBase* ov); template OverlayImplBase* handle_CLOSED_to_xxx(OverlayImplBase* ov); /* States here */ utils::eOverlayState mState; }; //------------------------State Traits -------------------------- // primary has nothing template struct StateTraits {}; /* * For 3D_xxx we need channel ID besides the FBx since * get crop/position 3D need that to determine pos/crop * info. * */ template <> struct StateTraits { typedef overlay::GenericPipe pipe0; //prim video typedef overlay::NullPipe pipe1; // place holder typedef overlay::NullPipe pipe2; // place holder typedef Rotator rot0; typedef NullRotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::GenericPipe pipe0; //prim video typedef overlay::VideoExtPipe pipe1; //ext video typedef overlay::GenericPipe pipe2; //ext subtitle typedef Rotator rot0; typedef Rotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::NullPipe pipe0; //nothing on primary with mdp typedef overlay::VideoExtPipe pipe1; //ext video typedef overlay::GenericPipe pipe2; //ext subtitle typedef NullRotator rot0; typedef Rotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::M3DPrimaryPipe pipe0; typedef overlay::NullPipe pipe1; // place holder typedef overlay::NullPipe pipe2; // place holder typedef Rotator rot0; typedef NullRotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::S3DPrimaryPipe pipe0; typedef overlay::S3DPrimaryPipe pipe1; typedef overlay::NullPipe pipe2; // place holder typedef Rotator rot0; typedef Rotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::S3DExtPipe pipe0; typedef overlay::S3DExtPipe pipe1; typedef overlay::NullPipe pipe2; // place holder typedef NullRotator rot0; typedef NullRotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::M3DPrimaryPipe pipe0; typedef overlay::M3DExtPipe pipe1; typedef overlay::NullPipe pipe2; // place holder typedef Rotator rot0; typedef NullRotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::UIMirrorPipe pipe0; typedef overlay::NullPipe pipe1; // place holder typedef overlay::NullPipe pipe2; // place holder typedef Rotator rot0; typedef NullRotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::GenericPipe pipe0; typedef overlay::VideoExtPipe pipe1; typedef overlay::UIMirrorPipe pipe2; typedef Rotator rot0; typedef Rotator rot1; typedef Rotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::GenericPipe pipe0; typedef overlay::NullPipe pipe1; // place holder typedef overlay::NullPipe pipe2; // place holder typedef NullRotator rot0; typedef NullRotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::GenericPipe pipe0; typedef overlay::GenericPipe pipe1; typedef overlay::NullPipe pipe2; // place holder typedef NullRotator rot0; typedef NullRotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::GenericPipe pipe0; typedef overlay::GenericPipe pipe1; typedef overlay::GenericPipe pipe2; typedef NullRotator rot0; typedef NullRotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { typedef overlay::GenericPipe pipe0; typedef overlay::NullPipe pipe1; typedef overlay::NullPipe pipe2; typedef NullRotator rot0; typedef NullRotator rot1; typedef NullRotator rot2; typedef overlay::OverlayImpl ovimpl; }; //------------------------Inlines -------------------------------- inline OverlayState::OverlayState() : mState(utils::OV_CLOSED){} inline OverlayState::~OverlayState() {} inline utils::eOverlayState OverlayState::state() const { return mState; } inline OverlayImplBase* OverlayState::reset(utils::eOverlayState s) { return handleEvent(s, 0); } inline void OverlayState::dump() const { ALOGE("== Dump state %d start/end ==", mState); } inline OverlayImplBase* OverlayState::handleEvent(utils::eOverlayState toState, OverlayImplBase* ov) { OverlayImplBase* newov = ov; // at least, we return the same if (mState != toState) { ALOGD_IF(DEBUG_OVERLAY, "%s: state changed %s-->%s", __FUNCTION__, getStateString(mState), getStateString(toState)); } else { ALOGD_IF(DEBUG_OVERLAY, "%s: no state change, state=%s", __FUNCTION__, getStateString(toState)); return newov; } switch(mState) { case utils::OV_CLOSED: newov = handle_from(toState, ov); break; case utils::OV_2D_VIDEO_ON_PANEL: newov = handle_from(toState, ov); break; case utils::OV_2D_VIDEO_ON_PANEL_TV: newov = handle_from(toState, ov); break; case utils::OV_2D_VIDEO_ON_TV: newov = handle_from(toState, ov); break; case utils::OV_3D_VIDEO_ON_2D_PANEL: newov = handle_from(toState, ov); break; case utils::OV_3D_VIDEO_ON_3D_PANEL: newov = handle_from(toState, ov); break; case utils::OV_3D_VIDEO_ON_3D_TV: newov = handle_from(toState, ov); break; case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: newov = handle_from(toState, ov); break; case utils::OV_UI_MIRROR: newov = handle_from(toState, ov); break; case utils::OV_2D_TRUE_UI_MIRROR: newov = handle_from(toState, ov); break; case utils::OV_BYPASS_1_LAYER: newov = handle_from(toState, ov); break; case utils::OV_BYPASS_2_LAYER: newov = handle_from(toState, ov); break; case utils::OV_BYPASS_3_LAYER: newov = handle_from(toState, ov); break; case utils::OV_DUAL_DISP: newov = handle_from(toState, ov); break; default: OVASSERT(1 == 0, "%s: unknown state = %d", __FUNCTION__, mState); } return newov; } template inline OverlayImplBase* OverlayState::handle_from(utils::eOverlayState toState, OverlayImplBase* ov) { switch(toState) { case utils::OV_CLOSED: ov = handle_xxx_to_CLOSED(ov); break; case utils::OV_2D_VIDEO_ON_PANEL: ov = handle_from_to(ov); break; case utils::OV_2D_VIDEO_ON_PANEL_TV: ov = handle_from_to(ov); break; case utils::OV_2D_VIDEO_ON_TV: ov = handle_from_to(ov); break; case utils::OV_3D_VIDEO_ON_2D_PANEL: ov = handle_from_to(ov); break; case utils::OV_3D_VIDEO_ON_3D_PANEL: ov = handle_from_to(ov); break; case utils::OV_3D_VIDEO_ON_3D_TV: ov = handle_from_to(ov); break; case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: ov = handle_from_to(ov); break; case utils::OV_UI_MIRROR: ov = handle_from_to(ov); break; case utils::OV_2D_TRUE_UI_MIRROR: ov = handle_from_to(ov); break; case utils::OV_BYPASS_1_LAYER: ov = handle_from_to(ov); break; case utils::OV_BYPASS_2_LAYER: ov = handle_from_to(ov); break; case utils::OV_BYPASS_3_LAYER: ov = handle_from_to(ov); break; case utils::OV_DUAL_DISP: ov = handle_from_to(ov); break; default: OVASSERT(1 == 0, "%s: unknown state = %d", __FUNCTION__, toState); } mState = toState; return ov; } /* Transition default from any to any. Does in two steps. * Moves from OLD to CLOSED and then from CLOSED to NEW */ template inline OverlayImplBase* OverlayState::handle_from_to(OverlayImplBase* ov) { handle_xxx_to_CLOSED(ov); return handle_CLOSED_to_xxx(ov); } //---------------Specializations------------- /* Transition from CLOSED to ANY */ template inline OverlayImplBase* OverlayState::handle_CLOSED_to_xxx( OverlayImplBase* /*ignored*/) { //If going from CLOSED to CLOSED, nothing to do. if(TO_STATE == utils::OV_CLOSED) return NULL; ALOGD("FROM_STATE = %s TO_STATE = %s", utils::getStateString(utils::OV_CLOSED), utils::getStateString(TO_STATE)); OverlayImplBase* ov = new typename StateTraits::ovimpl; RotatorBase* rot0 = new typename StateTraits::rot0; RotatorBase* rot1 = new typename StateTraits::rot1; RotatorBase* rot2 = new typename StateTraits::rot2; if(!ov->init(rot0, rot1, rot2)) { ALOGE("Overlay failed to init in state %d", TO_STATE); return 0; } return ov; } /* Transition from ANY to CLOSED */ template inline OverlayImplBase* OverlayState::handle_xxx_to_CLOSED(OverlayImplBase* ov) { //If going from CLOSED to CLOSED, nothing to do. if(FROM_STATE == utils::OV_CLOSED) return NULL; ALOGD("FROM_STATE = %s TO_STATE = %s", utils::getStateString(FROM_STATE), utils::getStateString(utils::OV_CLOSED)); OVASSERT(ov, "%s: ov is null", __FUNCTION__); if(!ov->close()) { ALOGE("%s: Failed to ov close", __FUNCTION__); } delete ov; ov = 0; return 0; } /* Transition from 2D_VIDEO_ON_PANEL to 2D_VIDEO_ON_PANEL_TV */ template<> inline OverlayImplBase* OverlayState::handle_from_to< utils::OV_2D_VIDEO_ON_PANEL, utils::OV_2D_VIDEO_ON_PANEL_TV>( OverlayImplBase* ov) { OVASSERT(ov, "%s: ov is null", __FUNCTION__); ALOGD("FROM_STATE = %s TO_STATE = %s", utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL), utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL_TV)); // Create new ovimpl based on new state typedef StateTraits NewState; OverlayImplBase* newov = new NewState::ovimpl; //copy pipe0/rot0 (primary video) newov->copyOvPipe(ov, utils::OV_PIPE0); //close old pipe1, create new pipe1 ov->closePipe(utils::OV_PIPE1); RotatorBase* rot1 = new NewState::rot1; newov->initPipe(rot1, utils::OV_PIPE1); //close old pipe2, create new pipe2 ov->closePipe(utils::OV_PIPE2); RotatorBase* rot2 = new NewState::rot2; newov->initPipe(rot2, utils::OV_PIPE2); // All pipes are copied or deleted so no more need for previous ovimpl delete ov; ov = 0; return newov; } /* Transition from 2D_VIDEO_ON_PANEL_TV to 2D_VIDEO_ON_PANEL */ template<> inline OverlayImplBase* OverlayState::handle_from_to< utils::OV_2D_VIDEO_ON_PANEL_TV, utils::OV_2D_VIDEO_ON_PANEL>( OverlayImplBase* ov) { OVASSERT(ov, "%s: ov is null", __FUNCTION__); ALOGD("FROM_STATE = %s TO_STATE = %s", utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL_TV), utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL)); // Create new ovimpl based on new state typedef StateTraits NewState; OverlayImplBase* newov = new NewState::ovimpl; //copy pipe0/rot0 (primary video) newov->copyOvPipe(ov, utils::OV_PIPE0); //close old pipe1, create new pipe1 ov->closePipe(utils::OV_PIPE1); RotatorBase* rot1 = new NewState::rot1; newov->initPipe(rot1, utils::OV_PIPE1); //close old pipe2, create new pipe2 ov->closePipe(utils::OV_PIPE2); RotatorBase* rot2 = new NewState::rot2; newov->initPipe(rot2, utils::OV_PIPE2); // All pipes are copied or deleted so no more need for previous ovimpl delete ov; ov = 0; return newov; } /* Transition from 2D_VIDEO_ON_PANEL_TV to 2D_VIDEO_ON_TV */ template<> inline OverlayImplBase* OverlayState::handle_from_to< utils::OV_2D_VIDEO_ON_PANEL_TV, utils::OV_2D_VIDEO_ON_TV>( OverlayImplBase* ov) { OVASSERT(ov, "%s: ov is null", __FUNCTION__); ALOGD("FROM_STATE = %s TO_STATE = %s", utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL_TV), utils::getStateString(utils::OV_2D_VIDEO_ON_TV)); // Create new ovimpl based on new state typedef StateTraits NewState; OverlayImplBase* newov = new NewState::ovimpl; //close old pipe0, create new pipe0 ov->closePipe(utils::OV_PIPE0); RotatorBase* rot0 = new NewState::rot0; newov->initPipe(rot0, utils::OV_PIPE0); //copy pipe1/rot1 (ext video) newov->copyOvPipe(ov, utils::OV_PIPE1); //copy pipe2/rot2 (ext cc) newov->copyOvPipe(ov, utils::OV_PIPE2); // All pipes are copied or deleted so no more need for previous ovimpl delete ov; ov = 0; return newov; } /* Transition from 2D_VIDEO_ON_TV to 2D_VIDEO_ON_PANEL_TV */ template<> inline OverlayImplBase* OverlayState::handle_from_to< utils::OV_2D_VIDEO_ON_TV, utils::OV_2D_VIDEO_ON_PANEL_TV>( OverlayImplBase* ov) { OVASSERT(ov, "%s: ov is null", __FUNCTION__); ALOGD("FROM_STATE = %s TO_STATE = %s", utils::getStateString(utils::OV_2D_VIDEO_ON_TV), utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL_TV)); // Create new ovimpl based on new state typedef StateTraits NewState; OverlayImplBase* newov = new NewState::ovimpl; //close old pipe0, create new pipe0 ov->closePipe(utils::OV_PIPE0); RotatorBase* rot0 = new NewState::rot0; newov->initPipe(rot0, utils::OV_PIPE0); //copy pipe1/rot1 (ext video) newov->copyOvPipe(ov, utils::OV_PIPE1); //copy pipe2/rot2 (ext cc) newov->copyOvPipe(ov, utils::OV_PIPE2); // All pipes are copied or deleted so no more need for previous ovimpl delete ov; ov = 0; return newov; } } // overlay #endif // OVERLAY_STATE_H