2014-12-12 4 views
0

Мне удалось выяснить, как захватить видеокадр из VideoView, который воспроизводит видео, хранящееся локально на телефоне. Однако, когда видео передается по IP-адресу в VideoView, очень сложно сделать снимок экрана/изображения/видео. Я был бы признателен за решение этой проблемы.Как захватить снимок экрана VideoView при потоковой передаче видео в Android

Вот аналогичный вопрос, который не получил ответа: How to capture a frame from video in android?

Вот решение для захвата видеокадра (ТОЛЬКО если видео хранится на телефоне):

public static Bitmap captureVideoFrame(Activity activity, VideoView vv, String viewSource, int currPosInMs) 
    { 
     MediaMetadataRetriever mmRetriever = new MediaMetadataRetriever(); 
     mmRetriever.setDataSource(viewSource); 

     Bitmap bmFrame = mmRetriever.getFrameAtTime(currPosInMs * 1000); // unit in microsecond 

     if(bmFrame == null){ 
      Toast.makeText(activity.getApplicationContext(), "Bitmap is null! Curr Position: " + currPosInMs, Toast.LENGTH_SHORT).show(); 
     } 
     else 
     { 
      Toast.makeText(activity.getApplicationContext(), "Bitmap is not null! Curr Position: " + currPosInMs, Toast.LENGTH_SHORT).show(); 

      // Save file 
      String mPath = Environment.getExternalStorageDirectory().toString() + "/" + SCREENSHOT_DIRECTORY + "myScreenshot.png"; 
      OutputStream fout = null; 
      File imageFile = new File(mPath); 

      try { 
       fout = new FileOutputStream(imageFile); 
       bmFrame.compress(Bitmap.CompressFormat.JPEG, 100, fout); 
       fout.flush(); 
       fout.close(); 

       Toast.makeText(activity.getApplicationContext(), "Saved file successfully!", Toast.LENGTH_SHORT).show(); 
      } 
      catch(Exception e){ 

      } 
     } 

     return bmFrame; 
    } 

ответ

0

Я нашел решение этой проблемы. Похоже, что VideoView не позволяет этого из-за низкого уровня аппаратного GPU при использовании SurfaceView.

Решение состоит в использовании TextureView и использовании MediaPlayer для воспроизведения видеоизображения внутри него. Управлению необходимо будет реализовать TextureView.SurfaceTextureListener. При съемке скриншота с этим решением видео замерзает на короткое время. Кроме того, TextureView не отображает пользовательский интерфейс по умолчанию для индикатора хода воспроизведения (воспроизведение, пауза, FF/RW, время воспроизведения и т. Д.). Это один из недостатков. Если у вас есть другое решение, пожалуйста, дайте мне знать :)

Вот решение:

public class TextureViewActivity extends Activity 
    implements TextureView.SurfaceTextureListener, 
       OnBufferingUpdateListener, 
       OnCompletionListener, 
       OnPreparedListener, 
       OnVideoSizeChangedListener 
{ 
    private MediaPlayer mp; 
    private TextureView tv; 
    public static String MY_VIDEO = "https://www.blahblahblah.com/myVideo.mp4"; 
    public static String TAG = "TextureViewActivity"; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_texture_view); 

     tv = (TextureView) findViewById(R.id.textureView1); 
     tv.setSurfaceTextureListener(this); 
    } 

    public void getBitmap(TextureView vv) 
    { 
     String mPath = Environment.getExternalStorageDirectory().toString() 
       + "/Pictures/" + Utilities.getDayTimeString() + ".png"; 
     Toast.makeText(getApplicationContext(), "Capturing Screenshot: " + mPath, Toast.LENGTH_SHORT).show(); 

     Bitmap bm = vv.getBitmap(); 
     if(bm == null) 
      Log.e(TAG,"bitmap is null"); 

     OutputStream fout = null; 
     File imageFile = new File(mPath); 

     try { 
      fout = new FileOutputStream(imageFile); 
      bm.compress(Bitmap.CompressFormat.PNG, 90, fout); 
      fout.flush(); 
      fout.close(); 
     } catch (FileNotFoundException e) { 
      Log.e(TAG, "FileNotFoundException"); 
      e.printStackTrace(); 
     } catch (IOException e) { 
      Log.e(TAG, "IOException"); 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.media_player_video, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle action bar item clicks here. The action bar will 
     // automatically handle clicks on the Home/Up button, so long 
     // as you specify a parent activity in AndroidManifest.xml. 
     int id = item.getItemId(); 
     if (id == R.id.action_settings) { 
      return true; 
     } 
     return super.onOptionsItemSelected(item); 
    } 

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

     try 
     { 
      mp = new MediaPlayer(); 
      mp.setDataSource(MY_VIDEO); 
      mp.setSurface(s); 
      mp.prepare(); 

      mp.setOnBufferingUpdateListener(this); 
      mp.setOnCompletionListener(this); 
      mp.setOnPreparedListener(this); 
      mp.setOnVideoSizeChangedListener(this); 

      mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
      mp.start(); 

      Button b = (Button) findViewById(R.id.textureViewButton); 
      b.setOnClickListener(new OnClickListener(){ 

       @Override 
       public void onClick(View v) 
       { 
        TextureViewActivity.this.getBitmap(tv); 
       } 
      }); 
     } 
     catch (IllegalArgumentException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (SecurityException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IllegalStateException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    }