[ERROR/EXCEPTION] Mediaplayer 파일 재생 불가(내부저장소 접근 불가) + 내/외부 저장소 접근

2021. 4. 23. 19:06Android/개발 CASE

  • Error Message

you store your tempfile in the application cache directory and the problem is that the MediaPlayer doesn't have access rights to application directories.

Instead you should passing a FileDescriptor to your MediaPlayer with setDataSource(FileDescriptor fd).   

 

  • 원인  
    • prepare failed status 0xFFFFFFFC  
    • prepare() 수행중에 해당 에러가 나는 경우가 있다.(IOException의 e.getMessage() 를 출력한 결과)
    • 여러가지 이유때문인 것으로 추정된다.
    • 의심해야 할 항목은 setDataSource가 읽어드린 데이터에 대해 player가 판단하지 못한 경우이다.  
      • header가 잘못된 파일을 읽었을 경우  
      • 읽어드린 범위가 잘못된 경우 (예컨데 - setDataSource(fd, 0, 0); )  
      • 다운로드 파일을 재생하려고 application 폴더 영역을 datasource로 사용한 경우.  

 

먼저 게시판에 흔하게 보이는 코드이며..저 역시 사용한 코드는 다음과 같으며.. 그뒤 두번째가...위의 충고(?)를 바탕으로
작성된 코드입니다. 참고로... 흔히 보이는 코드 (아래 첫번째꺼) 로는 http:// .... 로 직접 접근해서 플레이하는건 잘됩니다.

 

try {

MediaPlayer mediaPlayer = new MediaPlayer();

mediaPlayer.setDataSource(pathinlocal+FileName);

mediaPlayer.prepare();   ---- 여기에서 런타임 에러 발생 Prepare failed : status = 0x105.mediaPlayer.start();

} catch (IOException e) {

// handle exception

//((EditText) ((Activity) mMain).findViewById(R.id.txtStatus)).setText(e.getMessage());

}

 

아래는 위의 충고를 바탕으로 작성되어 문제가 해결된 코드입니다.

 

try {

MediaPlayer mediaPlayer = new MediaPlayer();

FileInputStream fis = new FileInputStream(pathinlocal+FileName);

FileDescriptor fd = fis.getFD();

mediaPlayer.setDataSource(fd);

mediaPlayer.prepare();

mediaPlayer.start();

} catch (IOException e) {

// handle exception

//((EditText) ((Activity) mMain).findViewById(R.id.txtStatus)).setText(e.getMessage());

}

 


Android 내부/외부 저장소

 

  • 내부 저장소   
    • 해당 앱만 접근 가능하며, 외부 앱의 접근은 불가  
    • 캐시파일은 디바이스 저장 공간 부족할 시 삭제 당할 수 있음  
    • /data/user/[User number]/[package name]/   
    • 경로 얻는 법
      • getDataDir().getAbsolutePath()                    
      • getFilesDir().getAbsolutePath()                    
      • getCacheDir().getAbsolutePath()  
                  
  • 외부 저장소   
    • 외부 앱에서 공통적으로 접근 가능한 영역  
    • write/read에 permission이 필요  
    • App 전용 폴더 : /storage/emulated/0/Android/data/[package name]/
      • App 삭제 시 동시에 삭제되므로 다른 App에서 공유하고자 하는 data 저장 금지
      • 경로 얻는 법
        • getExternalCacheDir().getAbsolutePath()                               
        • getExternalFilesDir(Environment.DIRECTORY_PICTURES)                              
    • 공용 폴더 : /storage/emulated/0/[Content 종류]
      • App이 삭제되어도 data는 남아있음 
      • 경로 얻는 법
        • Environment.getExternalStorageDirectory()
        • Environmnet.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)

 

참고 url : https://codechacha.com/ko/android-data-storage/


 

  •     파일 디스크립터(File Descriptor)란?   

리눅스와 유닉스에서는 시스템을 전부 파일로 처리하여 관리한다. (하드웨어 등 모든 장치도 포함)

시스템에서 프로세스가 파일에 접근하기 위한 방법으로 파일 디스크립터(FIle Descriptor)라는 핸들이 필요하다.

해당 파일을 open할때( 해당파일에 접근할 때 ) 파일 디스크립터는 0부터 N까지 즉, 음수가 아닌 0부터 차례대로 숫자를 부여받으며,

0, 1, 2는 프로세스가 메모리에서 실행을 시작할때 기본적으로 할당되는 파일 디스크립터이다.

 

참고 url : https://go-it.tistory.com/3

 


 

  •     패키지의 assets/audio/oh.mp3 플레이  
AssetFileDescriptor afd = getAssets().openFd("audio/oh.mp3");

MediaPlayer  audio_play = new MediaPlayer();
audio_play.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
audio_play.start();   

 

  •     패키지의 res/raw/oh.mp3 플레이  
MediaPlayer  audio_play = MediaPlayer.create(context, R.raw.oh);
audio_play.start();


 

  •     파일시스템의 /data/oh.mp3 플레이  
MediaPlayer  audio_play = new MediaPlayer();
audio_play.setDataSource("/data/oh.mp3");
audio_play.start();


 

[비디오 재생]  

  •     파일시스템의 /data/oh.mp4 플레이  
VideoView video = (VideoView) findViewById(R.id.video);
MediaController nc = new MediaController(this);
nc.setMediaPlayer(video);
video.setVideoPath("/data/oh.mp4");
video.start();  

 

  •     패키지의 res/raw/oh.mp4 플레이  
    VideoView에서는 패키지의 리소스 파일 재생 불가하며 직접 MediaPlayer를 이용해야함.

=> http://www.mailinglistarchive.com/android-developers@googlegroups.com/msg06223.html

 

출처: https://ecogeo.tistory.com/248 [아키텍트를 꿈꾸며 - 에코지오]