2015-02-03 5 views
2

Я реализую функцию, которая может увеличивать или уменьшать масштаб при воспроизведении потоковой передачи RTMP с помощью объекта SurfaceView. Я провел некоторое исследование, и я решил сначала рассчитать размер и позицию и использовать метод onMeasure() для повторной сборки представления.Как реализовать масштабируемое масштабирование SMOOTHLY в Android? Релевантно для SurfaceView с потоковой RTMP

Теперь у меня есть проблема, что объект действительно не соответствует положению, которое я установил во время масштабирования. Эффект, который я хотел бы реализовать, выглядит так: video (который показывает поведение версии iOS моего приложения), и я записал another video, чтобы показать, что я сделал до сих пор. Объект будет меняться чаще, если я использую ту же позицию, что и приложение для версии iOS. Он не является гладким и может привести к плохой работе с пользователем.

Мое наблюдение за поведением заключается в том, что объект SurfaceView изменил бы его ширину и высоту с фиксированным положением x и y при срабатывании функции масштабирования. Затем объект будет смещаться назад, что может возникнуть после выполнения макета его родителя. Я распечатал сообщения журнала и обнаружил, что положение x и y было бы изменено при запуске onMeasure(). Хотя я установил положение в функции, он все равно будет изменен, когда процесс перейдет к onLayout(). Поскольку onLayout() вызывается, как только onMeasure() закончен, поэтому я не вижу никаких возможных времен, чтобы установить положение, чтобы избежать смещения.

Ниже то, что я сделал: Layout:

<RelativeLayout 
    android:id="@+id/RelaytiveView" 
    android:layout_width="fill_parent" 
    android:layout_height="200dp"> 
    <LinearLayout 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:layout_centerInParent="true" 
     android:background="#000000" 
     android:gravity="center" 
     android:orientation="vertical" > 
     <com.player.adapter.RtmpLiveSurfaceview 
      android:id="@+id/goLiveView" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" /> 
    </LinearLayout> 
</RelativeLayout> 

И код:

public class RtmpLiveSurfaceview extends SurfaceView 
{ 
    private static final int DEFAULT_PIXEL_WIDTH = 1280; 
    private static final int DEFAULT_PIXEL_HEIGHT = 720; 
    private float INIT_WIDTH; 
    private float INIT_HEIGHT; 
    private float WIDTH = 0; 
    private float HEIGHT = 0; 
    private float SCALER = (float) 1.0; 
    private float TAG_POINT_X = 0; 
    private float TAG_POINT_Y = 0; 

    private float INIT_DIST = 0; 
    SurfaceHolder mholder; 

    static final int ZOOM = 2; 

    @Override 
    protected void onSizeChanged (int w, int h, int oldw, int oldh) 
    { 
    } 
    @Override 
    protected void onLayout (boolean changed, int left, int top, int right, int bottom) 
    { 
     setX(TAG_POINT_X); 
     setY(TAG_POINT_Y); 
    } 
    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
    { 
     int width = getDefaultSize(DEFAULT_PIXEL_WIDTH, widthMeasureSpec); 
     int height = getDefaultSize(DEFAULT_PIXEL_HEIGHT, heightMeasureSpec); 
     if (DEFAULT_PIXEL_WIDTH > 0 && DEFAULT_PIXEL_HEIGHT > 0) 
     { 
      if (DEFAULT_PIXEL_WIDTH * height > width * DEFAULT_PIXEL_HEIGHT) 
      { 
       height = width * DEFAULT_PIXEL_HEIGHT/DEFAULT_PIXEL_WIDTH; 
      } 
      else if (DEFAULT_PIXEL_WIDTH * height < width * DEFAULT_PIXEL_HEIGHT) 
      { 
       width = height * DEFAULT_PIXEL_WIDTH/DEFAULT_PIXEL_HEIGHT; 
      } 
      else 
      { 
      } 
     } 
     INIT_WIDTH = width; 
     INIT_HEIGHT = height; 
     if(WIDTH == 0) 
     { 
      WIDTH = INIT_WIDTH; 
      HEIGHT = INIT_HEIGHT; 
     } 
     int wmode = MeasureSpec.getMode(widthMeasureSpec); 
     int hmode = MeasureSpec.getMode(heightMeasureSpec); 
     int widthSpec = MeasureSpec.makeMeasureSpec((int)WIDTH, wmode); 
     int heightSpec = MeasureSpec.makeMeasureSpec((int)HEIGHT, hmode); 
     setX(TAG_POINT_X); 
     setY(TAG_POINT_Y); 
     super.onMeasure(widthSpec, heightSpec); 
    } 
    public void init() 
    { 
     mholder = getHolder(); 
     mholder.setSizeFromLayout(); 
     mholder.addCallback(new Callback() 
     { 
      @Override 
      public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
      { 
      } 
     }); 
    } 

    public boolean onTouchEvent(MotionEvent MEvent) 
    { 
     switch (MEvent.getAction() & MotionEvent.ACTION_MASK) 
     { 
      case MotionEvent.ACTION_POINTER_DOWN: 
      { 
       if(MEvent.getPointerCount() >= 2) 
       { 
        mode = ZOOM; 
        INIT_DIST = spacing(MEvent); 
        break; 
       } 
      } 
      case MotionEvent.ACTION_MOVE: 
      { 
       if (mode == ZOOM) 
       { 
        if(MEvent.getPointerCount() >= 2) 
        { 
         float newDist = spacing(MEvent); 
         float tmp_scaler = (float) (((newDist - INIT_DIST) * 0.1 + INIT_DIST)/INIT_DIST); 
         if((tmp_scaler * WIDTH) > (2.0 * INIT_WIDTH)) 
          tmp_scaler = (float) (((newDist - INIT_DIST) * 0.01 + INIT_DIST)/INIT_DIST); 
         WIDTH = getWidth(); 
         HEIGHT = getHeight(); 
         if (((tmp_scaler * WIDTH) >= (1.0 * INIT_WIDTH)) && ((tmp_scaler * WIDTH) <= (4.0 * INIT_WIDTH))) 
         { 
          SCALER = tmp_scaler; 
          TAG_POINT_X = getX(); 
          if((TAG_POINT_X + WIDTH * SCALER) < INIT_WIDTH) 
           TAG_POINT_X = INIT_WIDTH - WIDTH * SCALER; 
          else if(TAG_POINT_X > 0) 
           TAG_POINT_X = 0; 
          TAG_POINT_Y = getY(); 
          if((TAG_POINT_Y + HEIGHT * SCALER) < INIT_HEIGHT) 
           TAG_POINT_Y = INIT_HEIGHT - HEIGHT * SCALER; 
          else if(TAG_POINT_Y > 0) 
           TAG_POINT_Y = 0; 
          WIDTH = WIDTH * SCALER; 
          HEIGHT = HEIGHT * SCALER; 
          requestLayout(); 
         } 
        } 
       } 
       break; 
      } 

     } 

     return true; 
    } 
} 

Может кто-нибудь мне помочь? Если невозможно реализовать функцию масштабирования с увеличением с помощью SurfaceView, есть ли предлагаемое решение? Благодарю.

ответ

1

Перемещение и изменение размера SurfaceView, вероятно, не является правильным ответом. Поверхностная часть SurfaceView представляет собой отдельный слой, размер и положение которого управляется диспетчером окон, а не иерархией представления приложения, поэтому анимирование атрибутов SurfaceView имеет тенденцию выглядеть сумасшедшим.

Одним из возможных подходов было бы перейти от SurfaceView к TextureView. Вы можете избавиться от кода макета и просто использовать матрицу преобразования TextureView. См., Например, разницу в отношении соотношения сторон видео в классах воспроизведения фильмов Grafika - PlayMoveSurfaceActivity .clickPlayStop() использует AspectFrameLayout, а PlayMovieActivity .clickPlayStop() оставляет только один вид и просто изменяет матрицу ,

Другим подходом является сохранение SurfaceView, но отправьте предварительный просмотр камеры на SurfaceTexture и визуализируйте вывод на текстуру OpenGL ES. См. Пример TextureFromCameraActivity. Обратите внимание, что функция масштабирования реализована путем обновления координат текстуры. Это намного более гибко, но вам нужно будет установить код установки GLES.

+0

Благодарим вас за ответ! Я все еще работаю над этим, и я сообщу об этом позже на этой неделе. Надеюсь, это сработает! –