2017-03-23 3 views
1

Ich spiele Video in benutzerdefinierten Textureview. aber Breite konnte nicht richtig passen.Video nimmt nicht die volle Breite während der Wiedergabe von Video

My Custom Texture Ansicht

public class TextureVideoView extends TextureView 
    implements MediaPlayerControl { 
    private String TAG = "TextureVideoView"; 
    // settable by the client 
    private Uri mUri; 
    private Map<String, String> mHeaders; 

    // all possible internal states 
    private static final int STATE_ERROR    = -1; 
    private static final int STATE_IDLE    = 0; 
    public static final int STATE_PREPARING   = 1; 
    private static final int STATE_PREPARED   = 2; 
    private static final int STATE_PLAYING   = 3; 
    private static final int STATE_PAUSED    = 4; 
    private static final int STATE_PLAYBACK_COMPLETED = 5; 

    // mCurrentState is a TextureVideoView object's current state. 
    // mTargetState is the state that a method caller intends to reach. 
    // For instance, regardless the TextureVideoView object's current state, 
    // calling pause() intends to bring the object to a target state 
    // of STATE_PAUSED. 
    private int mCurrentState = STATE_IDLE; 
    private int mTargetState = STATE_IDLE; 

    // All the stuff we need for playing and showing a video 
    private Surface  mSurface = null; 
    private MediaPlayer mMediaPlayer = null; 
    private int   mAudioSession; 
    private int   mVideoWidth; 
    private int   mVideoHeight; 
    private int   mSurfaceWidth; 
    private int   mSurfaceHeight; 
    private MediaController mMediaController; 
    private OnCompletionListener mOnCompletionListener; 
    private MediaPlayer.OnPreparedListener mOnPreparedListener; 
    private int   mCurrentBufferPercentage; 
    private OnErrorListener mOnErrorListener; 
    private OnInfoListener mOnInfoListener; 
    private int   mSeekWhenPrepared; // recording the seek position while preparing 
    private boolean  mCanPause; 
    private boolean  mCanSeekBack; 
    private boolean  mCanSeekForward; 
    private Context mContext; 

    private ScaleType mScaleType; 

    private boolean isMute; 


    public enum ScaleType { 
     CENTER_CROP, TOP, BOTTOM 
    } 

    public TextureVideoView(Context context) { 
     super(context); 
     initVideoView(); 
    } 

    public TextureVideoView(Context context, AttributeSet attrs) { 
     this(context, attrs, 0); 
     initVideoView(); 
    } 

    public TextureVideoView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     initVideoView(); 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", " 
     //  + MeasureSpec.toString(heightMeasureSpec) + ")"); 

     int width = getDefaultSize(mVideoWidth, widthMeasureSpec); 
     int height = getDefaultSize(mVideoHeight, heightMeasureSpec); 

     if (mVideoWidth > 0 && mVideoHeight > 0) { 

      int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 
      int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 
      int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 
      int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 

      if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) { 
       // the size is fixed 
       width = widthSpecSize; 
       height = heightSpecSize; 

       // for compatibility, we adjust size based on aspect ratio 
       if (mVideoWidth * height < width * mVideoHeight) { 
        //Log.i("@@@", "image too wide, correcting"); 
        width = height * mVideoWidth/mVideoHeight; 
       } else if (mVideoWidth * height > width * mVideoHeight) { 
        //Log.i("@@@", "image too tall, correcting"); 
        height = width * mVideoHeight/mVideoWidth; 
       } 
      } else if (widthSpecMode == MeasureSpec.EXACTLY) { 
       // only the width is fixed, adjust the height to match aspect ratio if possible 
       width = widthSpecSize; 
       height = width * mVideoHeight/mVideoWidth; 
       if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { 
        // couldn't match aspect ratio within the constraints 
        height = heightSpecSize; 
       } 
      } else if (heightSpecMode == MeasureSpec.EXACTLY) { 
       // only the height is fixed, adjust the width to match aspect ratio if possible 
       height = heightSpecSize; 
       width = height * mVideoWidth/mVideoHeight; 
       if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { 
        // couldn't match aspect ratio within the constraints 
        width = widthSpecSize; 
       } 
      } else { 
       // neither the width nor the height are fixed, try to use actual video size 
       width = mVideoWidth; 
       height = mVideoHeight; 
       if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { 
        // too tall, decrease both width and height 
        height = heightSpecSize; 
        width = height * mVideoWidth/mVideoHeight; 
       } 
       if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { 
        // too wide, decrease both width and height 
        width = widthSpecSize; 
        height = width * mVideoHeight/mVideoWidth; 
       } 
      } 
     } else { 
      // no size yet, just adopt the given spec sizes 
     } 
     LogUtil.w("LOG_TAG", "Mesured Width -->" + width + "Mesured Height is -->" + height); 
     setMeasuredDimension(width, height); 
     // super.onMeasure(widthMeasureSpec,heightMeasureSpec); 
    } 

    @Override 
    public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 
     super.onInitializeAccessibilityEvent(event); 
     event.setClassName(TextureVideoView.class.getName()); 
    } 

    @Override 
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 
     super.onInitializeAccessibilityNodeInfo(info); 
     info.setClassName(TextureVideoView.class.getName()); 
    } 

    private void initVideoView() { 
     mScaleType=ScaleType.BOTTOM; 
     mContext = getContext(); 
     mVideoWidth = 0; 
     mVideoHeight = 0; 
     setSurfaceTextureListener(mSurfaceTextureListener); 
     setFocusable(true); 
     setFocusableInTouchMode(true); 
     requestFocus(); 
     mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>(); 
     mCurrentState = STATE_IDLE; 
     mTargetState = STATE_IDLE; 
    } 

    public void setVideoPath(String path) { 
     setVideoURI(Uri.parse(path)); 
    } 

    public void setVideoURI(Uri uri) { 
     setVideoURI(uri, null); 
    } 


    public int getMediaState(){ 

     return mCurrentState; 
    } 

    /** 
    * @hide 
    */ 
    public void setVideoURI(Uri uri, Map<String, String> headers) { 
     LogUtil.e("LOG_TAG","TextureVideoView-->"+ uri); 
     mUri = uri; 
     mHeaders = headers; 
     mSeekWhenPrepared = 0; 
     openVideo(); 
     requestLayout(); 
     invalidate(); 
    } 

    private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks; 

    public void stopPlayback() { 
     if (mMediaPlayer != null) { 
      mUri=null; 
      mMediaPlayer.stop(); 
      mMediaPlayer.release(); 
      mMediaPlayer = null; 
      mCurrentState = STATE_IDLE; 
      mTargetState = STATE_IDLE; 
     } 
    } 

    private void openVideo() { 
     if (mUri == null || mSurface == null) { 
      // not ready for playback just yet, will try again later 
      return; 
     } 
     // Tell the music playback service to pause 
     // TODO: these constants need to be published somewhere in the framework. 
     Intent i = new Intent("com.android.music.musicservicecommand"); 
     i.putExtra("command", "pause"); 
     mContext.sendBroadcast(i); 

     // we shouldn't clear the target state, because somebody might have 
     // called start() previously 
     release(false); 
     try { 
      mMediaPlayer = new MediaPlayer(); 

      if (mAudioSession != 0) { 
       mMediaPlayer.setAudioSessionId(mAudioSession); 
      } else { 
       mAudioSession = mMediaPlayer.getAudioSessionId(); 
      } 
      mMediaPlayer.setOnPreparedListener(mPreparedListener); 
      mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); 
      mMediaPlayer.setOnCompletionListener(mCompletionListener); 
      mMediaPlayer.setOnErrorListener(mErrorListener); 
      mMediaPlayer.setOnInfoListener(mInfoListener); 
      mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); 
      mCurrentBufferPercentage = 0; 
      mMediaPlayer.setDataSource(mContext, mUri, mHeaders); 
      mMediaPlayer.setSurface(mSurface); 
      mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 
      mMediaPlayer.setScreenOnWhilePlaying(true); 
      mMediaPlayer.prepareAsync(); 

      // we don't set the target state here either, but preserve the 
      // target state that was there before. 
      mCurrentState = STATE_PREPARING; 
      attachMediaController(); 
     } catch (IOException ex) { 
      Log.w(TAG, "Unable to open content: " + mUri, ex); 
      mCurrentState = STATE_ERROR; 
      mTargetState = STATE_ERROR; 
      mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); 
      return; 
     } catch (IllegalArgumentException ex) { 
      Log.w(TAG, "Unable to open content: " + mUri, ex); 
      mCurrentState = STATE_ERROR; 
      mTargetState = STATE_ERROR; 
      mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); 
      return; 
     } finally { 
      mPendingSubtitleTracks.clear(); 
     } 
    } 

    private void attachMediaController() { 
     if (mMediaPlayer != null && mMediaController != null) { 
      mMediaController.setMediaPlayer(this); 
      View anchorView = this.getParent() instanceof View ? 
       (View)this.getParent() : this; 
      mMediaController.setAnchorView(anchorView); 
      mMediaController.setEnabled(isInPlaybackState()); 
     } 
    } 

    MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = 
     new MediaPlayer.OnVideoSizeChangedListener() { 
      public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { 
       mVideoWidth = mp.getVideoWidth(); 
       mVideoHeight = mp.getVideoHeight(); 
       if (mVideoWidth != 0 && mVideoHeight != 0) { 
        getSurfaceTexture().setDefaultBufferSize(mVideoWidth, mVideoHeight); 
        requestLayout(); 
       } 
      } 
     }; 

    MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() { 
     public void onPrepared(MediaPlayer mp) { 
      mCurrentState = STATE_PREPARED; 

      mCanPause = mCanSeekBack = mCanSeekForward = true; 

      if (mOnPreparedListener != null) { 
       mOnPreparedListener.onPrepared(mMediaPlayer); 
      } 
      if (mMediaController != null) { 
       mMediaController.setEnabled(true); 
      } 
      mVideoWidth = mp.getVideoWidth(); 
      mVideoHeight = mp.getVideoHeight(); 

      LogUtil.w("LOG_TAG","Video Width is -->"+ mVideoWidth + "Video Height is -->"+ mVideoHeight); 

      int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call 
      if (seekToPosition != 0) { 
       seekTo(seekToPosition); 
      } 
      if (mVideoWidth != 0 && mVideoHeight != 0) { 
       //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight); 
       getSurfaceTexture().setDefaultBufferSize(mVideoWidth, mVideoHeight); 
       if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) { 
        // We didn't actually change the size (it was already at the size 
        // we need), so we won't get a "surface changed" callback, so 
        // start the video here instead of in the callback. 
        if (mTargetState == STATE_PLAYING) { 
         start(); 
         if (mMediaController != null) { 
          mMediaController.show(); 
         } 
        } else if (!isPlaying() && 
         (seekToPosition != 0 || getCurrentPosition() > 0)) { 
         if (mMediaController != null) { 
          // Show the media controls when we're paused into a video and make 'em stick. 
          mMediaController.show(0); 
         } 
        } 
       } 
      } else { 
       // We don't know the video size yet, but should start anyway. 
       // The video size might be reported to us later. 
       if (mTargetState == STATE_PLAYING) { 
        start(); 
       } 
      } 
     } 
    }; 

    private OnCompletionListener mCompletionListener = 
     new OnCompletionListener() { 
      public void onCompletion(MediaPlayer mp) { 
      if (mCurrentState == STATE_PLAYBACK_COMPLETED) { 
       // sprylab bugfix: on some devices onCompletion is called twice 
       return; 
      } 
       mCurrentState = STATE_PLAYBACK_COMPLETED; 
       mTargetState = STATE_PLAYBACK_COMPLETED; 
       if (mMediaController != null) { 
        mMediaController.hide(); 
       } 
       if (mOnCompletionListener != null) { 
        mOnCompletionListener.onCompletion(mMediaPlayer); 
       } 
      } 
     }; 

    private OnInfoListener mInfoListener = 
     new OnInfoListener() { 
      public boolean onInfo(MediaPlayer mp, int arg1, int arg2) { 
       if (mOnInfoListener != null) { 
        mOnInfoListener.onInfo(mp, arg1, arg2); 
       } 
       return true; 
      } 
     }; 

    private OnErrorListener mErrorListener = 
     new OnErrorListener() { 
      public boolean onError(MediaPlayer mp, int framework_err, int impl_err) { 
       Log.d(TAG, "Error: " + framework_err + "," + impl_err); 
       mCurrentState = STATE_ERROR; 
       mTargetState = STATE_ERROR; 
       if (mMediaController != null) { 
        mMediaController.hide(); 
       } 

      /* If an error handler has been supplied, use it and finish. */ 
       if (mOnErrorListener != null) { 
        if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) { 
         return true; 
        } 
       } 

      /* Otherwise, pop up an error dialog so the user knows that 
      * something bad has happened. Only try and pop up the dialog 
      * if we're attached to a window. When we're going away and no 
      * longer have a window, don't bother showing the user an error. 
      */ 
       if (getWindowToken() != null) { 
        Resources r = mContext.getResources(); 
        int messageId; 

        if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { 
         messageId = R.string.VideoView_error_text_invalid_progressive_playback; 
        } else { 
         messageId = R.string.VideoView_error_text_unknown; 
        } 

        new AlertDialog.Builder(mContext) 
         .setMessage(messageId) 
         .setPositiveButton(R.string.VideoView_error_button, 
          new DialogInterface.OnClickListener() { 
           public void onClick(DialogInterface dialog, int whichButton) { 
             /* If we get here, there is no onError listener, so 
             * at least inform them that the video is over. 
             */ 
            if (mOnCompletionListener != null) { 
             mOnCompletionListener.onCompletion(mMediaPlayer); 
            } 
           } 
          }) 
         .setCancelable(false) 
         .show(); 
       } 
       return true; 
      } 
     }; 

    private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = 
     new MediaPlayer.OnBufferingUpdateListener() { 
      public void onBufferingUpdate(MediaPlayer mp, int percent) { 
       mCurrentBufferPercentage = percent; 
      } 
     }; 

    /** 
    * Register a callback to be invoked when the media file 
    * is loaded and ready to go. 
    * 
    * @param l The callback that will be run 
    */ 
    public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) 
    { 
     mOnPreparedListener = l; 
    } 

    /** 
    * Register a callback to be invoked when the end of a media file 
    * has been reached during playback. 
    * 
    * @param l The callback that will be run 
    */ 
    public void setOnCompletionListener(OnCompletionListener l) 
    { 
     mOnCompletionListener = l; 
    } 

    /** 
    * Register a callback to be invoked when an error occurs 
    * during playback or setup. If no listener is specified, 
    * or if the listener returned false, TextureVideoView will inform 
    * the user of any errors. 
    * 
    * @param l The callback that will be run 
    */ 
    public void setOnErrorListener(OnErrorListener l) 
    { 
     mOnErrorListener = l; 
    } 

    /** 
    * Register a callback to be invoked when an informational event 
    * occurs during playback or setup. 
    * 
    * @param l The callback that will be run 
    */ 
    public void setOnInfoListener(OnInfoListener l) { 
     mOnInfoListener = l; 
    } 

    SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener() 
    { 
     @Override 
     public void onSurfaceTextureSizeChanged(final SurfaceTexture surface, final int width, final int height) { 
      mSurfaceWidth = width; 
      mSurfaceHeight = height; 
      boolean isValidState = (mTargetState == STATE_PLAYING); 
      boolean hasValidSize = (mVideoWidth == width && mVideoHeight == height); 
      if (mMediaPlayer != null && isValidState && hasValidSize) { 
       if (mSeekWhenPrepared != 0) { 
        seekTo(mSeekWhenPrepared); 
       } 
       start(); 
      } 
     } 

     @Override 
     public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) { 
      mSurface = new Surface(surface); 
      openVideo(); 


     } 

     @Override 
     public boolean onSurfaceTextureDestroyed(final SurfaceTexture surface) { 
      // after we return from this we can't use the surface any more 
      if (mSurface != null) { 
       mSurface.release(); 
       mSurface = null; 
      } 
      if (mMediaController != null) mMediaController.hide(); 
      release(true); 
      return true; 
     } 
     @Override 
     public void onSurfaceTextureUpdated(final SurfaceTexture surface) { 
      // do nothing 
     } 
    }; 


    @Override 
    protected void onDetachedFromWindow() { 
     super.onDetachedFromWindow(); 

     if(mUri!=null){ 
      LogUtil.e("LOG_TAG","TextureVideo View is hidden-->"+ mUri.getPath()); 
      stopPlayback(); 
     } 

    } 

    /* 
     * release the media player in any state 
     */ 
    private void release(boolean cleartargetstate) { 
     if (mMediaPlayer != null) { 
      mMediaPlayer.reset(); 
      mMediaPlayer.release(); 
      mMediaPlayer = null; 
      mPendingSubtitleTracks.clear(); 
      mCurrentState = STATE_IDLE; 
      if (cleartargetstate) { 
       mTargetState = STATE_IDLE; 
      } 
     } 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent ev) { 
     if (isInPlaybackState() && mMediaController != null) { 
      toggleMediaControlsVisiblity(); 
     } 
     return false; 
    } 

    @Override 
    public boolean onTrackballEvent(MotionEvent ev) { 
     if (isInPlaybackState() && mMediaController != null) { 
      toggleMediaControlsVisiblity(); 
     } 
     return false; 
    } 

    @Override 
    public boolean onKeyDown(int keyCode, KeyEvent event) 
    { 
     boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && 
      keyCode != KeyEvent.KEYCODE_VOLUME_UP && 
      keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && 
      keyCode != KeyEvent.KEYCODE_VOLUME_MUTE && 
      keyCode != KeyEvent.KEYCODE_MENU && 
      keyCode != KeyEvent.KEYCODE_CALL && 
      keyCode != KeyEvent.KEYCODE_ENDCALL; 
     if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) { 
      if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || 
       keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { 
       if (mMediaPlayer.isPlaying()) { 
        pause(); 
        mMediaController.show(); 
       } else { 
        start(); 
        mMediaController.hide(); 
       } 
       return true; 
      } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { 
       if (!mMediaPlayer.isPlaying()) { 
        start(); 
        mMediaController.hide(); 
       } 
       return true; 
      } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP 
       || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { 
       if (mMediaPlayer.isPlaying()) { 
        pause(); 
        mMediaController.show(); 
       } 
       return true; 
      } else { 
       toggleMediaControlsVisiblity(); 
      } 
     } 

     return super.onKeyDown(keyCode, event); 
    } 

    private void toggleMediaControlsVisiblity() { 
     if (mMediaController.isShowing()) { 
      mMediaController.hide(); 
     } else { 
      mMediaController.show(); 
     } 
    } 

    @Override 
    public void start() { 
     if (isInPlaybackState()) { 
      mMediaPlayer.start(); 
      mCurrentState = STATE_PLAYING; 
     } 
     mTargetState = STATE_PLAYING; 
    } 

    @Override 
    public void pause() { 
     if (isInPlaybackState()) { 
      if (mMediaPlayer.isPlaying()) { 
       mMediaPlayer.pause(); 
       Constants.VIDEO_LENGTH = 0; 
       Constants.VIDEO_LENGTH = mMediaPlayer.getCurrentPosition(); 
       mCurrentState = STATE_PAUSED; 
      } 
     } 
     mTargetState = STATE_PAUSED; 
    } 

    public void suspend() { 
     release(false); 
    } 

    public void resume() { 
     openVideo(); 
    } 

    @Override 
    public int getDuration() { 
     if (isInPlaybackState()) { 
      return mMediaPlayer.getDuration(); 
     } 
     return -1; 
    } 

    @Override 
    public int getCurrentPosition() { 
     if (isInPlaybackState()) { 
      return mMediaPlayer.getCurrentPosition(); 
     } 
     return 0; 
    } 

    @Override 
    public void seekTo(int msec) { 
     if (isInPlaybackState()) { 
      mMediaPlayer.seekTo(msec); 
      mSeekWhenPrepared = 0; 
     } else { 
      mSeekWhenPrepared = msec; 
     } 
    } 

    @Override 
    public boolean isPlaying() { 
     return isInPlaybackState() && mMediaPlayer.isPlaying(); 
    } 

    @Override 
    public int getBufferPercentage() { 
     if (mMediaPlayer != null) { 
      return mCurrentBufferPercentage; 
     } 
     return 0; 
    } 

    private boolean isInPlaybackState() { 
     return (mMediaPlayer != null && 
      mCurrentState != STATE_ERROR && 
      mCurrentState != STATE_IDLE && 
      mCurrentState != STATE_PREPARING); 
    } 

    @Override 
    public boolean canPause() { 
     return mCanPause; 
    } 

    @Override 
    public boolean canSeekBackward() { 
     return mCanSeekBack; 
    } 

    @Override 
    public boolean canSeekForward() { 
     return mCanSeekForward; 
    } 

    public int getAudioSessionId() { 
     if (mAudioSession == 0) { 
      MediaPlayer foo = new MediaPlayer(); 
      mAudioSession = foo.getAudioSessionId(); 
      foo.release(); 
     } 
     return mAudioSession; 
    } 
} 

nach diese Textur Ansicht mit i Video wie dieses video

und ich brauche, wie diese Video image

bitte vorschlagen, was soll ich voll zu tun, um immer bin zu füllen Breite

Antwort

0

ändern Sie diese Zeile:

mScaleType=ScaleType.BOTTOM; 

zu

mScaleType=ScaleType.FIT_XY; 

Wenn Sie noch gleiche Problem haben dann Ihre Layouts überprüfen, wo Wiedergabe von Video Start in match_parent oder not.and setzen Ihre scaleType.FIT_XY im fnction gesetzt.

Verwandte Themen