Reputation: 1586
I'm building video player with android media player object. i'm able to hear the audio but the video does not appear on surfaceView. here is my code
public class PlayerActivity extends Activity implements SurfaceHolder.Callback {
String path;
private MediaPlayer mp;
private SurfaceView mPreview;
private SurfaceHolder holder;
boolean pausing = false;
public static String filepath;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
getWindow().setFormat(PixelFormat.UNKNOWN);
mPreview = (SurfaceView)findViewById(R.id.surfaceView);
holder = mPreview.getHolder();
holder.setFixedSize(176, 144);
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mp = new MediaPlayer();
mp.setDisplay(holder);
try {
Intent intent = getIntent();
Uri fileuri = intent.getData();
filepath=fileuri.getPath();
} catch(Exception e) {}
try {
mp.setDataSource(filepath);
mp.prepare();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mp.start();
}
}
target is android 2.3 and above. how to fix it please help me..
Upvotes: 13
Views: 36942
Reputation: 268
Kotlin user - You can use MediaPlayer with SurfaceView like following example. Just create VideoLayout
class with following codes.
class VideoLayout(
context: Context, attrs: AttributeSet?
) : FrameLayout(context, attrs), SurfaceTextureListener {
private var isLoop: Boolean
private var isSound: Boolean
private var videoAlign: Int
private var videoScale: Int
private var mVideoWidth = 0f
private var mVideoHeight = 0f
private var fileName: String? = null
private var fileFormat: FileFormat = FILE
private var videoSurface: TextureView? = null
private var mediaPlayer: MediaPlayer? = null
enum class Scale {
ORIGINAL, CROP, STRETCH, FIT_SCREEN
}
enum class FileFormat {
FILE, URI, URL, OTHER
}
enum class Align {
TOP, TOP_LEFT, TOP_RIGHT, CENTER, CENTER_LEFT,
CENTER_RIGHT, BOTTOM, BOTTOM_LEFT, BOTTOM_RIGHT
}
init {
val styledAttributes = context.theme.obtainStyledAttributes(
attrs, R.styleable.VideoLayout, 0, 0
)
fileName = styledAttributes.getString(R.styleable.VideoLayout_path_or_url)
videoScale = styledAttributes.getInteger(R.styleable.VideoLayout_scaleType, 3)
videoAlign = styledAttributes.getInteger(R.styleable.VideoLayout_align, 4)
isLoop = styledAttributes.getBoolean(R.styleable.VideoLayout_loop, true)
isSound = styledAttributes.getBoolean(R.styleable.VideoLayout_sound, false)
styledAttributes.recycle()
fileName?.let {
setupView()
it.setFileFormat()
if (videoScale != 2) {
calculateVideoSize()
surfaceSetup()
}
}
}
private fun setupView() {
videoSurface = TextureView(context)
addView(videoSurface)
videoSurface?.surfaceTextureListener = this
}
private fun String.setFileFormat() {
fileFormat = if (contains("http://") || contains("https://")) {
URL
} else if (contains("content://")) {
URI
} else if(contains("file://")) {
FILE
} else {
OTHER
}
}
private fun calculateVideoSize() {
try {
val metaRetriever = MediaMetadataRetriever()
fileName?.let {
if (fileFormat != OTHER) {
when(fileFormat) {
FILE -> {
val fName = it.substringAfterLast('/')
val file = File(context.getExternalFilesDir(
Environment.DIRECTORY_DOWNLOADS), fName
)
Timber.d("$fName file exists: ${file.exists()}")
val fd = FileInputStream(file).fd
metaRetriever.setDataSource(fd)
}
URI -> {
val uri = it.toUri()
metaRetriever.setDataSource(context, uri)
}
else -> metaRetriever.setDataSource(it, HashMap())
}
} else {
val afd = context.assets.openFd(it)
metaRetriever.setDataSource(
afd.fileDescriptor, afd.startOffset, afd.length
)
}
}
metaRetriever.extractMetadata(METADATA_KEY_VIDEO_HEIGHT)?.let {
mVideoHeight = it.toFloat()
}
metaRetriever.extractMetadata(METADATA_KEY_VIDEO_WIDTH)?.let {
mVideoWidth = it.toFloat()
}
metaRetriever.release()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: NumberFormatException) {
e.printStackTrace()
}
}
private fun updateTextureViewSize(viewWidth: Int, viewHeight: Int) {
var scaleX = 1.0f
var scaleY = 1.0f
val viewWidthFloat = viewWidth.toFloat()
val viewHeightFloat = viewHeight.toFloat()
val viewWidthFactor = viewWidthFloat / viewHeightFloat
val videoWidthFactor = mVideoWidth / mVideoHeight
when (videoScale) {
0 -> { //original
scaleX = mVideoWidth / viewWidthFloat
scaleY = mVideoHeight / viewHeightFloat
}
1 -> { // crop
if (viewWidthFactor > videoWidthFactor) {
scaleY = ((viewWidthFloat / mVideoWidth) * mVideoHeight) / viewHeightFloat
} else {
scaleX = ((viewHeightFloat / mVideoHeight) * mVideoWidth) / viewWidthFloat
}
}
3 -> { // fit-screen
if (viewWidthFactor > videoWidthFactor) {
scaleX = ((viewHeightFloat / mVideoHeight) * mVideoWidth) / viewWidthFloat
} else {
scaleY = ((viewWidthFloat / mVideoWidth) * mVideoHeight) / viewHeightFloat
}
}
}
var pivotPointX = 0f
var pivotPointY = 0f
when (videoAlign) {
0 -> {
pivotPointX = viewWidthFloat / 2f
pivotPointY = 0f
}
1 -> {
pivotPointX = 0f
pivotPointY = 0f
}
2 -> {
pivotPointX = viewWidthFloat
pivotPointY = 0f
}
3 -> {
pivotPointX = viewWidthFloat / 2f
pivotPointY = viewHeightFloat / 2f
}
4 -> {
pivotPointX = 0f
pivotPointY = viewHeightFloat / 2f
}
5 -> {
pivotPointX = viewWidthFloat
pivotPointY = viewHeightFloat / 2f
}
6 -> {
pivotPointX = viewWidthFloat / 2f
pivotPointY = viewHeightFloat
}
7 -> {
pivotPointX = 0f
pivotPointY = viewHeightFloat
}
8 -> {
pivotPointX = viewWidthFloat
pivotPointY = viewHeightFloat
}
}
val matrix = Matrix().apply {
setScale(scaleX, scaleY, pivotPointX, pivotPointY)
}
videoSurface?.setTransform(matrix)
videoSurface?.layoutParams = LayoutParams(viewWidth, viewHeight)
}
private fun surfaceSetup() {
val screenHeight = resources.displayMetrics.heightPixels
val screenWidth = resources.displayMetrics.widthPixels
updateTextureViewSize(screenWidth, screenHeight)
}
private fun surfaceAvailableWorkers(surfaceTexture: SurfaceTexture) {
val surface = Surface(surfaceTexture)
try {
mediaPlayer = MediaPlayer()
mediaPlayer?.let { player ->
fileName?.let {
if (fileFormat != OTHER) {
when(fileFormat) {
FILE -> {
val fName = it.substringAfterLast('/')
val file = File(context.getExternalFilesDir(
Environment.DIRECTORY_DOWNLOADS), fName
)
Timber.d("$fName file exists: ${file.exists()}")
val fd = FileInputStream(file).fd
player.setDataSource(fd)
}
URI -> {
val uri = it.toUri()
player.setDataSource(context, uri)
}
else -> player.setDataSource(fileName)
}
} else {
val afd = context.assets.openFd(it)
player.setDataSource(afd.fileDescriptor, afd.startOffset, afd.length)
}
if (!isSound) player.setVolume(0f, 0f)
player.setSurface(surface)
player.isLooping = isLoop
player.prepareAsync()
player.setOnPreparedListener { obj: MediaPlayer -> obj.start() }
}
}
} catch (ignored: IllegalArgumentException) {
} catch (ignored: SecurityException) {
} catch (ignored: IllegalStateException) {
} catch (ignored: IOException) {
}
}
private fun changeVideo() {
try {
onDestroyVideoLayout()
mediaPlayer = MediaPlayer()
mediaPlayer?.let { player ->
fileName?.let {
if (fileFormat != OTHER) {
when(fileFormat) {
FILE -> {
val fName = it.substringAfterLast('/')
val file = File(context.getExternalFilesDir(
Environment.DIRECTORY_DOWNLOADS), fName
)
Timber.d("$fName file exists: ${file.exists()}")
val fd = FileInputStream(file).fd
player.setDataSource(fd)
}
URI -> {
val uri = it.toUri()
player.setDataSource(context, uri)
}
else -> player.setDataSource(fileName)
}
} else {
val afd = context.assets.openFd(it)
player.setDataSource(afd.fileDescriptor, afd.startOffset, afd.length)
}
if (!isSound) player.setVolume(0f, 0f)
player.isLooping = isLoop
player.setSurface(Surface(videoSurface?.surfaceTexture))
player.prepareAsync()
player.setOnPreparedListener { obj: MediaPlayer -> obj.start() }
}
}
} catch (ignored: IllegalArgumentException) {
} catch (ignored: IOException) {
} catch (ignored: IllegalStateException) {
} catch (ignored: SecurityException) {
}
}
override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
surfaceAvailableWorkers(surface)
}
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {}
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean = false
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {}
fun onDestroyVideoLayout() {
mediaPlayer?.let {
try {
it.stop()
it.release()
mediaPlayer = null
} catch (e: IllegalStateException) {
e.printStackTrace()
}
}
}
fun onResumeVideoLayout() {
mediaPlayer?.let {
if (!it.isPlaying) {
try {
it.start()
} catch (e: IllegalStateException) {
e.printStackTrace()
}
}
}
}
fun onPauseVideoLayout() {
mediaPlayer?.let {
if (it.isPlaying) {
try {
it.pause()
} catch (e: IllegalStateException) {
e.printStackTrace()
}
}
}
}
fun setPathOrUrl(fileName: String) {
this.fileName = fileName
fileName.setFileFormat()
if (videoSurface == null) {
setupView()
}
if (videoScale != 2) {
calculateVideoSize()
surfaceSetup()
}
if (videoSurface != null) {
changeVideo()
}
}
fun setIsLoop(isLoop: Boolean) {
this.isLoop = isLoop
}
fun setScale(scale: Scale) {
videoScale = scale.ordinal
}
fun setAlign(align: Align) {
videoAlign = align.ordinal
}
}
Add following to your layout.xml
<com.your.package.VideoLayout
android:id="@+id/video_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:loop="true"
app:sound="false"
app:scaleType="crop"
app:align="center"/>
Also this supports video scaleType
like center_crop
, fit_screen
, stretch
and original
.
Upvotes: 0
Reputation: 9
It is not working for me, throwing error illegal state exception in
surfaceCreated()
method at linemp.setDisplay(holder);
Declare mp.setDisplay(holder)
as given below :
@Override
public void surfaceCreated(SurfaceHolder holder)
{
mediaPlayer.setDataSource(this,uri);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.prepare();
mp.setDisplay(holder);
mp.start;
}
Upvotes: 0
Reputation: 1586
finally i fixed it myself. just called the mp.setDisplay(holder);
inside the surfaceCreated() function. and the final code is
public class PlayerActivity extends Activity implements SurfaceHolder.Callback {
String path;
private MediaPlayer mp;
private SurfaceView mPreview;
private SurfaceHolder holder;
boolean pausing = false;
public static String filepath;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
getWindow().setFormat(PixelFormat.UNKNOWN);
mPreview = (SurfaceView)findViewById(R.id.surfaceView);
holder = mPreview.getHolder();
holder.setFixedSize(800, 480);
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mp = new MediaPlayer();
try{
Intent intent = getIntent();
Uri fileuri = intent.getData();
filepath=fileuri.getPath();
}catch(Exception e){}
}
protected void onPause(){
super.onPause();
mp.release();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
mp.setDisplay(holder);
play();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
void play(){
try {
mp.setDataSource(filepath);
mp.prepare();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mp.start();
}
}
Upvotes: 28