2011-12-21 155 views
12

我的應用程序只提供肖像模式。在肖像活動中,我有一個全屏VideoView。我想要做的是在風景模式下將VideoView(實際視頻,視頻緩衝器)旋轉90度。啓用活動在Lanscape模式不是一種選擇。 擴展VideoView和畫布旋轉不起作用,因爲它是一個SurfaceView而不是實際的視圖。 有沒有什麼辦法可以通過videoView來實現呢?旋轉android VideoView

+2

爲什麼風景模式不是一個選項,當這是你想要的? – TouchBoarder 2012-10-14 19:50:56

回答

0

您可以在清單中單獨設置一個活動的排列方式,因此您的視頻可以橫向(和縱向)顯示,而其他應用程序都是縱向顯示。請參閱我的回答here以獲取解決方案。

+0

這是一個好主意,但如果您想在片段中顯示視頻而不是全屏,則無法工作。 – 2013-11-28 19:07:02

21

即使正確設置了合成矩陣並使用了旋轉屬性,VideoView也不支持旋轉視頻。

你可以做的是使用TextureView並設置其屬性rotation =「90」(例如)。然後它會旋轉框架,但縱橫比是你需要處理你自己的東西。爲了做到這一點,你可以使用textureView.setScaleX((screenHeight * 1.0F)/屏幕寬度)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <TextureView 
     android:id="@+id/playback_video" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_centerInParent="true" 
     android:rotation="90" /> 
</RelativeLayout> 

應該處理流式視頻了。但請把它看作一個例子而不是發佈現成的代碼。我重命名了一些東西並刪除了其他東西,它們與問題沒有關係,這可能會破壞某些東西,但通常這是可行的示例。

public class PlaybackActivity extends Activity implements MediaPlayer.OnErrorListener, OnPreparedListener, 
     OnCompletionListener, OnVideoSizeChangedListener, OnBufferingUpdateListener, OnInfoListener, 
     SurfaceTextureListener 
{ 

    private MediaPlayer mediaPlayer; 
    private TextureView videoView; 
    private boolean startedPlayback = false; 
    private boolean playerReady = false; 
    public static final int MEDIA_INFO_NETWORK_BANDWIDTH = 703; 

    private void createMediaPlayer() { 
     mediaPlayer = new MediaPlayer(); 
    } 

    private void releaseMediaPlayer() { 
     if (mediaPlayer != null) { 
      mediaPlayer.setSurface(null); 
      mediaPlayer.release(); 
      mediaPlayer = null; 
     } 
    } 

    public void onCompletion(MediaPlayer mp) { 
     Log.w(TAG, "Video playback finished"); 
    } 

    @Override 
    public boolean onError(MediaPlayer player, int what, int extra) { 
     if (what == MediaPlayer.MEDIA_ERROR_UNKNOWN) { 
      /* 
      * Restart play back in case we did not start anything yet. This may 
      * be the case when we tried to tune in in very first secs of the 
      * broadcast when there is no data yet. 
      */ 
      if (liveBroadcast && mediaPlayer != null && !mediaPlayer.isPlaying() && !startedPlayback) { 
       if (checkCount-- > 0) { 
        mediaPlayer.reset(); 
        checkBroadcast(); 
       } else { 
        Log.w(TAG, "Broadcast finished"); 
       } 
      } else { 
       Log.w(TAG, "No media in stream"); 
      } 
     } else if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) { 
      Log.w(TAG, "Media service died unexpectedly"); 
     } else { 
      Log.w(TAG, "Unknown media error"); 
     } 
     return true; 
    } 

    @Override 
    public boolean onInfo(MediaPlayer mp, int what, int extra) { 
     switch (what) { 
     case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING: 
      Log.w(TAG, "Media is too complex to decode it fast enough."); 
      startedPlayback = true; 
      break; 
     case MEDIA_INFO_NETWORK_BANDWIDTH: 
      Log.w(TAG, "Bandwith in recent past."); 
      break; 
     case MediaPlayer.MEDIA_INFO_BUFFERING_START: 
      Log.w(TAG, "Start of media bufferring."); 
      startedPlayback = true; 
      break; 
     case MediaPlayer.MEDIA_INFO_BUFFERING_END: 
      Log.w(TAG, "End of media bufferring."); 
      startedPlayback = true; 
      break; 
     case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING: 
      Log.w(TAG, "Media is not properly interleaved."); 
      break; 
     case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE: 
      Log.w(TAG, "Stream is not seekable."); 
      break; 
     case MediaPlayer.MEDIA_INFO_METADATA_UPDATE: 
      Log.w(TAG, "New set of metadata is available."); 
      break; 
     case MediaPlayer.MEDIA_INFO_UNKNOWN: 
     default: 
      Log.w(TAG, "Unknown playback info (" + what + ":" + extra + ")."); 
      break; 
     } 
     return true; 
    } 

    private void startPlayback() { 
     if (mediaPlayer != null) { 
      onLoaded(mediaPlayer); 
      mediaPlayer.start(); 
     } 
    } 

    private void pausePlayback() { 
     if (mediaPlayer != null && mediaPlayer.isPlaying()) 
      mediaPlayer.pause(); 
    } 

    private void resumePlayback() { 
     if (mediaPlayer != null && mediaPlayer.isPlaying()) 
      mediaPlayer.start(); 
    } 

    private void onLoaded(MediaPlayer mp) { 
    } 

    public void onPrepared(MediaPlayer mp) { 
     playerReady = true; 
     startPlayback(); 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 
     setContentView(R.layout.playback); 
     videoView = (TextureView) findViewById(R.id.playback_video); 
     videoView.setOnClickListener(videoViewClickHandler); 
     videoView.setSurfaceTextureListener(this); 
     createMediaPlayer(); 
    } 

    @Override 
    protected void onDestroy() { 
     releaseMediaPlayer(); 
     if (surface != null) { 
      surface.release(); 
      surface = null; 
     } 
     super.onDestroy(); 
    } 

    @Override 
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 
     this.surface = new Surface(surface); 
     loadMedia(someurl); 
    } 

    @Override 
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 
     if (this.surface != null) { 
      releaseMediaPlayer(); 
      this.surface.release(); 
      this.surface = null; 
     } 
     return true; 
    } 

    @Override 
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 
    } 

    @Override 
    public void onSurfaceTextureUpdated(SurfaceTexture surface) { 
    } 

    @Override 
    public void onVideoSizeChanged(MediaPlayer mp, int w, int h) { 
     if (w > 0 && h > 0 && !videoSizeSetupDone) { 
      Log.w(TAG, "Video size changed: " + w + "x" + h); 
      changeVideoSize(w, h); 
     } 
    } 

    private boolean videoSizeSetupDone = false; 

    private void changeVideoSize(int width, int height) { 
     DisplayMetrics metrics = new DisplayMetrics(); 
     RelativeLayout.LayoutParams params; 

     Utils.getScreenMetrics(this, metrics); 
     VideoOrientation orientation = someVideoSource.getVideoOrientation(); 
     if (orientation == LANDSCAPE) { 
      params = new RelativeLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels); 
     } else { 
      float rotation = orientation == BroadcastVideoOrientation.BroadcastVideoFrontCamera ? -90.0f : 90.0f; 
      params = new RelativeLayout.LayoutParams(metrics.heightPixels, metrics.widthPixels); 
      float scale = (width * 1.0f)/(height * 1.0f); 
      videoView.setRotation(rotation); 
      videoView.setScaleX(scale); 
     } 
     params.addRule(RelativeLayout.CENTER_IN_PARENT, -1); 
     videoView.setLayoutParams(params); 
     videoSizeSetupDone = true; 
    } 

    private void loadMedia(String url) { 
     if (surface == null) 
      return; 
     Log.d(App.TAG, "Loading url: " + url); 

     startedPlayback = false; 
     try { 
      mediaPlayer.reset(); 
      mediaPlayer.setSurface(surface); 
      mediaPlayer.setDataSource(url); 
      mediaPlayer.setOnPreparedListener(this); 
      mediaPlayer.setOnCompletionListener(this); 
      mediaPlayer.setOnErrorListener(this); 
      mediaPlayer.setOnVideoSizeChangedListener(this); 
      mediaPlayer.setScreenOnWhilePlaying(true); 
      mediaPlayer.setOnBufferingUpdateListener(this); 
      mediaPlayer.setOnInfoListener(this); 
      mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 
      mediaPlayer.prepareAsync(); 
     } catch (Exception e) { 
      Log.w(TAG, "Media load failed"); 
      Utils.alert(this, "Playback Error", e.getMessage(), finishHandler); 
     } 
    } 
} 

希望這會有所幫助。我一直在尋找這個解決方案很長一段時間。嘗試幾乎所有東西,這似乎是唯一的方法。

+1

你能解釋嗎... – sri 2013-11-26 06:15:20

+0

用兩個詞,這是OpenGL紋理表面,你可以用它做任何你喜歡的,伸展,鏡子等等。 – 2013-11-26 07:52:33

+0

@Umka請問你能告訴我hw我們能不能預覽鏡頭..任何代碼示例 – Aswathy 2014-01-02 09:22:36