美文网首页
MediaCodec+MediaExtractor实现选取本地视

MediaCodec+MediaExtractor实现选取本地视

作者: 小于先森 | 来源:发表于2019-12-25 19:00 被阅读0次

    mediacodec视频硬解码

    不喜欢多比比 直接上代码
    需要配置provider 适配7.0+ 具体怎么配置自行google

    package com.cyber.app_test.ui.aty
    
    import android.app.Activity
    import android.content.Intent
    import android.content.pm.ActivityInfo
    import android.os.Bundle
    import android.util.Log
    import android.view.Surface
    import android.view.SurfaceHolder
    import android.view.View
    import com.cyber.app_test.R
    import com.cyber.app_test.base.BaseActivity
    import kotlinx.android.synthetic.main.aty_videoplay.*
    import kotlinx.android.synthetic.main.include_title.*
    import android.R.attr.start
    import android.R.attr.configure
    import android.R.attr.mimeType
    import android.content.Context
    import android.media.MediaCodec
    import android.media.MediaCodec.createByCodecName
    import android.media.MediaFormat.createVideoFormat
    import android.media.MediaFormat.MIMETYPE_VIDEO_AVC
    import android.media.MediaCodec.createDecoderByType
    import android.media.MediaExtractor
    import android.media.MediaFormat
    import android.net.Uri
    import android.os.Build
    import android.support.v4.content.FileProvider
    import com.cyber.app_test.BuildConfig
    import com.cyber.app_test.utils.FileUtils
    import java.nio.ByteBuffer
    
    
    /***
     * 作者 : 于德海
     * 时间 : 2019/12/25 0025 15:05
     * 描述 :
     */
     class VideoPlayActivity : BaseActivity() {
        private val TAG = VideoPlayActivity::class.java.simpleName
        private var mSurface : Surface?=null
        private var mMediaCodec : MediaCodec? = null
        private var mContext : Context? = null
        private var isDestory = false
        override fun initParam(bundle: Bundle?) {
        }
    
        override fun initLayout(): Int {
            return R.layout.aty_videoplay
        }
    
        override fun initView() {
            tv_title.text = TAG
            mSurface = surfaceView.holder.surface
            surfaceView.holder.addCallback(callback)
            mContext = this
        }
    
    
        var callback : SurfaceHolder.Callback = object : SurfaceHolder.Callback{
            override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) {
                Log.i(TAG,"surfaceChanged")
            }
    
            override fun surfaceDestroyed(holder: SurfaceHolder?) {
                Log.i(TAG,"surfaceDestroyed")
            }
    
            override fun surfaceCreated(holder: SurfaceHolder?) {
            }
    
        }
    
    
        override fun initData() {
        }
    
        override fun initListener() {
            btn_select.setOnClickListener(View.OnClickListener { v ->kotlin.run {
                 var intent = Intent()
                intent.type = "*/*"
                intent.addCategory(Intent.CATEGORY_OPENABLE)
                 intent.action = Intent.ACTION_GET_CONTENT
                 startActivityForResult(intent,1)
            }  })
        }
    
        override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            super.onActivityResult(requestCode, resultCode, data)
            Log.i(TAG,"onActivityResult:$requestCode;$resultCode")
            if(requestCode == 1 && resultCode == Activity.RESULT_OK){
                Log.i(TAG,"data:"+data?.data)
                MediaThread(data?.data).start()
            }
        }
    
        override fun onClick(v: View?) {
        }
    
    
         inner class MediaThread : Thread{
             var framecount =0L
             var inputErrorCount = 0
             var outputErrorCount = 0
            var videoUri : Uri? = null
            constructor(uri : Uri?) : super(){
                videoUri = uri
            }
    
            override fun run() {
                super.run()
                var mediaExtractor  = MediaExtractor()
                val fileUrl = FileUtils.getFilePathByUri(this@VideoPlayActivity, videoUri)
                Log.i(TAG,"fileURl:$fileUrl")
                mediaExtractor.setDataSource(fileUrl)
                var index = getMediaTrackIndex(mediaExtractor)
                Log.i(TAG,"视频渠道:$index")
                if(index >= 0){
                    var mediaFormat = mediaExtractor.getTrackFormat(index)
                    var width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH)
                    var height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT)
    //                var duration = mediaFormat.getLong(MediaFormat.KEY_DURATION)/1000000
                    Log.i(TAG,"widht:$width;height:$height;mime:"+mediaFormat.getString(MediaFormat.KEY_MIME))
                    mediaExtractor.selectTrack(index)
                    mMediaCodec = createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME))
                    mMediaCodec?.configure(mediaFormat,mSurface,null,0)
                    mMediaCodec?.start()
                    var bufferInfo = MediaCodec.BufferInfo()
                    var inputbuffer = mMediaCodec?.inputBuffers
                    while (!isDestory){
                        inputData(mediaExtractor,inputbuffer)
                        outputData(bufferInfo)
    
                    }
    
                }
            }
    
             fun outputData(buffer: MediaCodec.BufferInfo){
                 var output = mMediaCodec?.dequeueOutputBuffer(buffer,20000L)!!
                 if(output>=0){
                     Log.i(TAG,"out time:$framecount")
                     mMediaCodec?.releaseOutputBuffer(output,true)
                     outputErrorCount = 0
                     return
                 }
                 if(outputErrorCount>10){
                     outputErrorCount =0
                     Log.e(TAG,"输出超过错误上限")
                     return
                 }
                 outputErrorCount++
                 outputData(buffer)
             }
             fun inputData(extractor: MediaExtractor,inputBuffer : Array<ByteBuffer>?){
                var index:Int = mMediaCodec?.dequeueInputBuffer(10000L)!!
    
                 if(index >= 0){
                     framecount++
                     var input : ByteBuffer? = null
                     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                         input = mMediaCodec?.getInputBuffer(index)
                     } else {
                         input = inputBuffer?.get(index)
                     }
                     var size = extractor.readSampleData(input,0)
                     Log.i(TAG,"inject:$framecount;size:$size")
                     var flag = 0
                     if(size < 0){
                         flag = MediaCodec.BUFFER_FLAG_END_OF_STREAM
                         Log.e(TAG,"视频结束")
                         isDestory = true
                         return
                     }
                     inputErrorCount = 0
                     mMediaCodec?.queueInputBuffer(index,0,size,framecount,flag)
                     extractor.advance()
                     return
                 }
    
                 if(inputErrorCount>10){
                     inputErrorCount =0
                     Log.e(TAG,"注入超过错误上限")
                     return
                 }
                 outputErrorCount++
                 inputData(extractor,inputBuffer)
             }
    
    
    
             fun getMediaTrackIndex(mediaExtractor: MediaExtractor) : Int{
                 for (i in 0 until mediaExtractor.trackCount){
                     var mediaFormat = mediaExtractor.getTrackFormat(i)
                     if (mediaFormat.getString(MediaFormat.KEY_MIME).startsWith("video/")){
                         return i
                     }
                 }
                 return -1
             }
    
        }
    
        override fun onDestroy() {
            isDestory = true
            super.onDestroy()
        }
    }
    

    FileUtils类

    此类是参考的别人的文章 具体连接找不到了 有认领的可@我

    package com.cyber.app_test.utils;
    
    import android.content.ContentResolver;
    import android.content.ContentUris;
    import android.content.Context;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Environment;
    import android.provider.DocumentsContract;
    import android.provider.MediaStore;
    
    /***
     * 作者 : 于德海
     * 时间 : 2019/12/25 0025 16:07
     * 描述 : 
     */
    public final class FileUtils {
    
        public static String getFilePathByUri(Context context, Uri uri) {
            String path = null;
            // 以 file:// 开头的
            if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
                path = uri.getPath();
                return path;
            }
            // 以 content:// 开头的,比如 content://media/extenral/images/media/17766
            if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()) && Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
                Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.Media.DATA}, null, null, null);
                if (cursor != null) {
                    if (cursor.moveToFirst()) {
                        int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                        if (columnIndex > -1) {
                            path = cursor.getString(columnIndex);
                        }
                    }
                    cursor.close();
                }
                return path;
            }
            // 4.4及之后的 是以 content:// 开头的,比如 content://com.android.providers.media.documents/document/image%3A235700
            if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                if (DocumentsContract.isDocumentUri(context, uri)) {
                    if (isExternalStorageDocument(uri)) {
                        // ExternalStorageProvider
                        final String docId = DocumentsContract.getDocumentId(uri);
                        final String[] split = docId.split(":");
                        final String type = split[0];
                        if ("primary".equalsIgnoreCase(type)) {
                            path = Environment.getExternalStorageDirectory() + "/" + split[1];
                            return path;
                        }
                    } else if (isDownloadsDocument(uri)) {
                        // DownloadsProvider
                        final String id = DocumentsContract.getDocumentId(uri);
                        final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
                                Long.valueOf(id));
                        path = getDataColumn(context, contentUri, null, null);
                        return path;
                    } else if (isMediaDocument(uri)) {
                        // MediaProvider
                        final String docId = DocumentsContract.getDocumentId(uri);
                        final String[] split = docId.split(":");
                        final String type = split[0];
                        Uri contentUri = null;
                        if ("image".equals(type)) {
                            contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                        } else if ("video".equals(type)) {
                            contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                        } else if ("audio".equals(type)) {
                            contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                        }
                        final String selection = "_id=?";
                        final String[] selectionArgs = new String[]{split[1]};
                        path = getDataColumn(context, contentUri, selection, selectionArgs);
                        return path;
                    }
                }
            }
            return null;
        }
    
        private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
            Cursor cursor = null;
            final String column = "_data";
            final String[] projection = {column};
            try {
                cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
                if (cursor != null && cursor.moveToFirst()) {
                    final int column_index = cursor.getColumnIndexOrThrow(column);
                    return cursor.getString(column_index);
                }
            } finally {
                if (cursor != null)
                    cursor.close();
            }
            return null;
        }
    
        private static boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        private static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        private static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
    }
    
    

    Over

    相关文章

      网友评论

          本文标题:MediaCodec+MediaExtractor实现选取本地视

          本文链接:https://www.haomeiwen.com/subject/vpetbctx.html