/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2007,
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM is free software; you can redistribute it and/or modify it    
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; only version 2 of the License.      
 * 
 * NMM is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 
 * License for more details.  
 * 
 * You should have received a copy of the GNU General Public License 
 * along with NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */


#ifndef _NMM_VIDEOMUXNODE_HPP_
#define _NMM_VIDEOMUXNODE_HPP_ _NMM_VIDEOMUXNODE_HPP_

#include "nmm/nmm_prefix.hpp"

#include "nmm/multimedia/GenericMultiplexerNode.hpp"
#include "nmm/multimedia/ISyncResetImpl.hpp"
#include "nmm/utils/scaler/VideoScaler.hpp"
#include "nmm/utils/thread/ThreadMutex.hpp"
#include "nmm/utils/interpolator/LinearInterpolator.hpp"
#include "IVideoMuxImpl.hpp"

namespace NMM {
    
  class VideoMuxNode :
    public GenericMultiplexerNode,
    public ISyncResetImpl,
    public IVideoMuxImpl
  {
  private:
    Buffer* in_buffer1; ///< stores buffer from input1
    Buffer* in_buffer2; ///< stores buffer from input2

    Timestamp current_timestamp; ///< stores the latest set and valid timestamp of incoming stream from input1

    ThreadMutex mutex; ///< mutex used to guard processBuffer from all method from IVideoMux

    size_t counter; ///< counter (for demo purposes only)

    int input1_width;  ///< stores width of video from input1
    int input1_height; ///< stores height of video from input1
    int input1_ratio_x;///< stores aspect x ratio of video from input1
    int input1_ratio_y;///< stores aspect y ratio of video from input1
    int input2_width;  ///< stores width of video from input2
    int input2_height; ///< stores height of video from input2
    int input2_ratio_x;///< stores aspect x ratio of video from input1
    int input2_ratio_y;///< stores aspect y ratio of video from input1
    int width1;        ///< stores scaled width of video from input1
    int height1;       ///< stores scaled height of video from input1
    int width2;        ///< stores scaled width of video from input2
    int height2;       ///< stores scaled height of video from input2
    int x_pos1;        ///< stores x position of video from input1
    int y_pos1;        ///< stores y position of video from input1
    int x_pos2;        ///< stores x position of video from input2
    int y_pos2;        ///< stores y position of video from input2

    IVideoMux::Alignment alignment1; ///< stores alignment of video from input1
    IVideoMux::Alignment alignment2; ///< stores alignment of video from input2
    int x_alignment1; ///< according to alignment1: top/left or bottom/right corner in x direction
    int y_alignment1; ///< according to alignment1: top/left or bottom/right corner in y direction
    int x_alignment2; ///< according to alignment2: top/left or bottom/right corner in x direction
    int y_alignment2; ///< according to alignment2: top/left or bottom/right corner in y direction

    int output_width;  ///< stores width of outgoing video ( = width of video from input 1 )
    int output_height; ///< stores height of outgoing video ( = height of video from input 1 )

    bool width_height_coupling1; ///< if true, only one of width or height needs to be controlled for input1
    bool width_height_coupling2; ///< if true, only one of width or height needs to be controlled for input2

    VideoScaler scaler; ///< helper for scaling video frames

    LinearInterpolator x_pos_interpolator1;  ///< interpolator
    LinearInterpolator y_pos_interpolator1;  ///< interpolator
    LinearInterpolator width_interpolator1;  ///< interpolator
    LinearInterpolator height_interpolator1; ///< interpolator
    LinearInterpolator x_pos_interpolator2;  ///< interpolator
    LinearInterpolator y_pos_interpolator2;  ///< interpolator
    LinearInterpolator width_interpolator2;  ///< interpolator
    LinearInterpolator height_interpolator2; ///< interpolator

    /**
     * Copies video frame (tmp) onto other frame (out)
     * @param out_data pointer to outgoing frame 
     * @param out_width widht of outgoing frame
     * @param out_height height of outgoing frame
     * @param out_x position in x direction from left, top-most corner for frame to copy
     * @param out_y position in y direction from left, top-most corner for frame to copy
     * @param tmp_data pointer to video frame to be copied
     * @param tmp_width widht of video frame to be copied
     * @param tmp_height height of video frame to be copied
     */
    void copyVideoFrame(char*& out_data, size_t out_width, size_t out_height, size_t out_x, size_t out_y, 
			char*& tmp_data, size_t tmp_width, size_t tmp_height);

  protected:

    /** filter out syncReset instream events */
    virtual Result syncReset();

    /** state transition */
    virtual Result doInit();
    /** state transition */
    virtual Result doInitOutput();
      
    /** IVideoMuxImpl */
    virtual Time getCurrentSyncTime();
    /** IVideoMuxImpl */
    virtual void setPosition(const string& input_jack_tag, const nmm_int32& x, const nmm_int32& y);
    /** IVideoMuxImpl */
    virtual void setXPositionControl(const string& input_jack_tag, const Time& start_time, const Time& end_time, const nmm_int32& start_x, const nmm_int32& end_x);
    /** IVideoMuxImpl */
    virtual void setYPositionControl(const string& input_jack_tag, const Time& start_time, const Time& end_time, const nmm_int32& start_y, const nmm_int32& end_y);
    /** IVideoMuxImpl */
    virtual void setSize(const string& input_jack_tag, const nmm_int32& size_x, const nmm_int32& size_y);
    /** IVideoMuxImpl */
    virtual void setWidthControl(const string& input_jack_tag, const Time& start_time, const Time& end_time, const nmm_int32& start_width, const nmm_int32& end_width, const IVideoMux::Alignment& align);
    /** IVideoMuxImpl */
  virtual void setHeightControl(const string& input_jack_tag, const Time& start_time, const Time& end_time, const nmm_int32& start_height, const nmm_int32& end_height, const IVideoMux::Alignment& align);
    /** IVideoMuxImpl */
    virtual void setWidthHeightCouplingEnabled(const string& input_jack_tag, const nmm_bool& enable);
    /** IVideoMuxImpl */
    virtual nmm_int32 getWidth(const string& input_jack_tag);
    /** IVideoMuxImpl */
    virtual nmm_int32 getHeight(const string& input_jack_tag);
    /** IVideoMuxImpl */
    virtual nmm_int32 getXPos(const string& input_jack_tag);
    /** IVideoMuxImpl */
    virtual nmm_int32 getYPos(const string& input_jack_tag);

    /** implements functionality of node */
    Message* processBuffer(Buffer*);
      
  public:
      
    VideoMuxNode(const char *name = "VideoMuxNode", StreamQueue::Mode = StreamQueue::MODE_SUSPEND, int = 10);
    ~VideoMuxNode();
  };
}
#include "nmm/nmm_suffix.hpp"

#endif
