안드로이드에서 플레이하기 위해서 VLC라이브러리를 빌드해야 한다.


빌드 방법은 VLC공식 사이트에 나와있다.


https://wiki.videolan.org/AndroidCompile/


리눅스에서 빌드를 해야하기 때문에 번거롭다.


그래서 아래에 빌드 결과물을 받을 수 있도록 하였다. 이 라이브러리는 구버전이기 때문에 직접 받아서 빌드하기를 추천한다.


libvlc.z01

libvlc.zip



이렇게 얻은 libvlc를 프로젝트에 추가한다.




우선 액티비티에 여러 인자를 Implement한다.

public class MainActivity extends AppCompatActivity implements IVLCVout.Callback, LibVLC.HardwareAccelerationError, TextureView.SurfaceTextureListener 

IVLCVout.Callback, LibVLC.HardwareAccelerationError, TextureView.SurfaceTextureListener를 implement한 이유는 콜백함수를 사용하기 위함이다.


각각의 기능은 아래에 설명한다.




IVLCVout.Callback는 비디오 실행시 콜백함수에 해당한다. 이 것을 위하여 아래의 세 함수를 작성해 주어야 한다.

@Override //VLC 레이아웃 설정
public void onNewLayout(IVLCVout vout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen) {
if (width * height == 0)
return;
// store video size
mVideoWidth = width;
mVideoHeight = height;
setSize(mVideoWidth, mVideoHeight);
}

@Override
public void onSurfacesCreated(IVLCVout ivlcVout) {

}

@Override
public void onSurfacesDestroyed(IVLCVout ivlcVout) {

}

위 세 함수는 각각 새 레이아웃 생성시, 화면 생성시, 화면 제거시 각각 동작한다.


비디오를 실행하면 비디오의 크기를 변경해주어야 한다. 비디오 사이즈는 TextureView의 사이즈를 변경해주면 된다.


LibVLC.HardwareAccelerationError는 하드웨어 가속에 에러가 생기면 어떠한 동작을 하는지 나타낸다.

@Override  //하드웨어 가속 에러시 플레이어 종료
public void eventHardwareAccelerationError() {
releasePlayer();
Toast.makeText(this, "Error with hardware acceleration", Toast.LENGTH_LONG).show();
}

하드웨어 가속중 에러가 생기면 플레이어를 종료하고 에러 토스트 메시지를 띄운다.


마지막으로 SurfaceTextureListener는 TextureView의 상태에 따라 동작하는 함수이다.

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

}

@Override //SurfaceTexture 화면(동영상 해상도 및 사이즈)에 따라 크기 변경
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
mVideoWidth = width;
mVideoHeight = height;
setSize(mVideoWidth, mVideoHeight);
}

@Override //SurfaceTexture 화면이 종료되었을때 종료
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
if(!(mMediaPlayer == null))
mMediaPlayer.release();
return true;
}

@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {

}

각각 텍스쳐뷰의 사용가능, 텍스쳐뷰의 크기 변화, 텍스쳐뷰의 제거, 텍스쳐뷰의 업데이트 시에 실행한다.


크기가 변하면(orientation의 변화) 동영상의 크기를 변화시킨다.


또한 텍스쳐뷰가 제거가 되면 비디오를 종료한다.



다음은 Mediaplayer.EventListener이다. 재생중에 어떠한 일이 발생하면 실행하는 함수이다.

//미디어 플레이어 리스너 클래스
private static class MyPlayerListener implements MediaPlayer.EventListener {
private WeakReference<MainActivity> mOwner;

//액티비티 변수를 받아오기 위하여 지정
private MyPlayerListener(MainActivity owner) {
mOwner = new WeakReference<>(owner);
}

@Override
public void onEvent(MediaPlayer.Event event) {
MainActivity player = mOwner.get();

switch(event.type) {
case MediaPlayer.Event.EndReached:
player.releasePlayer();
break;
case MediaPlayer.Event.Playing:
player.mSeekBar.setMax((int) player.mMediaPlayer.getLength());
player.mSeekBar.setOnSeekBarChangeListener(player.mSeekListener);
break;
case MediaPlayer.Event.Paused:
break;
case MediaPlayer.Event.Stopped:
break;
case MediaPlayer.Event.PositionChanged:
player.mSeekBar.setProgress((int)player.mMediaPlayer.getTime());
default:
break;
}
}
}

이 함수는 동영상이 플레이되는 중에 계속 호출된다.





아래는 VLC플레리어 실행을 위한 코드이다. 초기화 정보가 들어있다.

//VLC 플레이어 실행
private void createPlayer(String media) {
releasePlayer();
try {
if (media.length() > 0) {
Toast toast = Toast.makeText(this, media, Toast.LENGTH_LONG);
toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
0);
toast.show();
}

// Create LibVLC
ArrayList<String> options = new ArrayList<>();
//options.add("--subsdec-encoding <encoding>");
options.add("--aout=opensles");
options.add("--audio-time-stretch"); // time stretching
options.add("-vvv"); // verbosity
libvlc = new LibVLC(options);
libvlc.setOnHardwareAccelerationError(this);

mTexture.setKeepScreenOn(true);

// Create media player
mMediaPlayer = new MediaPlayer(libvlc);
mMediaPlayer.setEventListener(mPlayerListener);

// Set up video output
final IVLCVout vout = mMediaPlayer.getVLCVout();
vout.setVideoView(mTexture);
//vout.setSubtitlesView(mSurfaceSubtitles);
vout.addCallback(this);
vout.attachViews();

Media m = new Media(libvlc, media);
mMediaPlayer.setMedia(m);
mMediaPlayer.play();

} catch (Exception e) {
Toast.makeText(this, "Error creating player!", Toast.LENGTH_LONG).show();
}
}

코드를 요약하자면 비디오 실행 옵션설정, 콜백함수 설정, 플레이 할 비디오를 설정하고 재생시킨다.


여러가지 옵션는 VLC홈페이지에 나와있다.



VLC의 미디어플레이어는 안드로이드의 미디어플레이어와 사용법이 유사하다.


게다가 여러 재생옵션 기능을 제공한다. 


하지면 여러 콜백함수가 없어서 필요한 코드는 작성해주어야 한다.


이제 프로그램을 실행하고 play버튼을 누르면 동영상이 재생되면서 볼 수 있다.


모든 코드는 Github에 올려져있다.


Github : https://github.com/pchan1401-ICIL/VLCTestProject



출처 : http://androidarena.co.in/how-to-clear-or-kill-stack-of-activity-android/





Intent intent = new Intent(getApplicationContext(), NewActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

startActivity(intent);


새로운 액티비티 스택을 지우면서 새로운 액티비티를 생성하려면 인텐트에 플래그에 입력한다.


인터넷에서는 작동하는 경우도 있다.


하지만 어떤경우에서 작동이 안하는 경우가 있는데 아마 백그라운드에서 애니메이션처리같이 계속 동작하는 액티비티는 중지하지 않는 것 같다.


이런 경우 AndroidManifests.xml에 지워야 할 액티비티에 아래와같이 추가하면 된다.


android:noHistory="true"

위와 같이 추가하고 실행하면 액티비티 스택에 저장되지 않는다.


http://stackoverflow.com/a/21375102


위의 링크에서도 finish() 보다는 더 적절한 noHistory 설정을 적용시키는게 옳다고 나온다.

안드로이드 센서를 이용하다 보면 센서 값들에 정확도에 문제가 있다.


가속도계는 노이즈가 심하고, 자이로는 바이어스가 있다.


이러한 단점을 보완하기 위하여 센서를 합성해야 한다.


센서 합성은 수학적 지식이 있어야 한다.


보통은 그러한 지식이 없기 때문에 안드로이드에서는 내장함수로 계산을 도와준다.


Rotation Vector는 하나의 방향벡터와 방향벡터의 회전정도를 준다.


[출처 : https://en.wikipedia.org/wiki/Axis%E2%80%93angle_representation]


위 그림처럼 e는 방향을 나타내고, θ는 벡터가 시계 방향으로 회전한 정도를 나타낸다.


Android Developer : https://developer.android.com/reference/android/hardware/SensorEvent.html#values


안드로이드에서는 센서와 같게 사용하면 된다.

mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR), SensorManager.SENSOR_DELAY_UI);

value에서 출력되는 값은 다음과 같다.


  • values[0]: x*sin(θ/2)
  • values[1]: y*sin(θ/2)
  • values[2]: z*sin(θ/2)
  • values[3]: cos(θ/2)
  • values[4]: estimated heading Accuracy (in radians) (-1 if unavailable)

기존에 사용한 Orientation Sensor는 자이로를 사용하지 않아서 노이즈가 심했지만, Rotation Vector는 세개의 센서를 이용하여 각 센서의 단점을 보완했다



+ Recent posts