使用MediaExtractor和MediaMuxer完成视频的抽取并生成新的视频

不多说,上代码

这里是关于对视频抽取的直接操作

public class ExtractorMuxer  {
    public static  void divideMedia (@Nullable String srcPath, @Nullable String dstPath) throws IOException {
        MediaExtractor extractor = new MediaExtractor();
        extractor.setDataSource(srcPath);
        MediaMuxer muxer = new MediaMuxer(dstPath,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        MediaFormat format =null;
        int audioIndex =-1;
        int videoIndex =-1;
        for(int i=0;i<extractor.getTrackCount();i++){
            format = extractor.getTrackFormat(i);
            if(format.getString(MediaFormat.KEY_MIME).startsWith("audio")){
                audioIndex = i;
                continue;
            }
            if (format.getString(MediaFormat.KEY_MIME).startsWith("video")){
                videoIndex = i;

            }
        }
        int audioTrack = -1;
        int videoTrack = -1;
        audioTrack = muxer.addTrack(extractor.getTrackFormat(audioIndex));
        videoTrack = muxer.addTrack(extractor.getTrackFormat(videoIndex));
        muxer.start();
        extractor.selectTrack(audioIndex);
        writeIntoBuf(extractor,muxer,audioTrack);
        extractor.selectTrack(videoIndex);
        writeIntoBuf(extractor,muxer,videoTrack);


        muxer.stop();
        muxer.release();
        extractor.release();
    }

    private static void writeIntoBuf(@Nullable MediaExtractor extractor,@Nullable MediaMuxer mediaMuxer,int  track){
        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        info.presentationTimeUs =0;
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024*1024);
        if (extractor!=null&&mediaMuxer!=null) {
            while (true) {
                int size = extractor.readSampleData(byteBuffer, 0);
                if (size <= 0) {
                    
                    break;
                } else {
                    //当视频出现拖拉后花屏现象时,可能是info.flags设置成了MediaCodec.Buffer.Flag.Key.Frame了,MediaMuxer在写入时自动将其他帧视为I帧导致信息错误从而缺失P帧出现花屏。
                    info.flags = extractor.getSampleFlags();
                    info.offset = 0;
                    info.presentationTimeUs = extractor.getSampleTime();
                    info.size = size;
                    mediaMuxer.writeSampleData(track, byteBuffer, info);
                    extractor.advance();
                }
            }
        }
    }
}

这里是简单的利用systemvideoview完成视频的播放,由于需要拷贝到本地存储,所以略微复杂了一些

 */
public class MainActivity extends Activity {

    String filePath=null;

    String path=null;
    private VideoView systemVideoView;

    private MediaController mediaController;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout);

        filePath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/map1.mp4";
         path  = Environment.getExternalStorageDirectory().getAbsolutePath()+"/map4.mp4";
        systemVideoView = findViewById(R.id.videoView);
        mediaController = new MediaController(this);
        mediaController.show();
        systemVideoView.setMediaController(mediaController);
        if (verifyPermissino(this)) {
           Log.v("tag", "写入sdcard");
            saveToSDCard(filePath, getResources().openRawResource(R.raw.shape_of_my_heart));
        }
        try {
            ExtractorMuxer.divideMedia(filePath,path);
        } catch (IOException e) {
            e.printStackTrace();
        }

        systemVideoView.setVideoURI(Uri.fromFile(new File(path)));


    }



    private void saveToSDCard(String filename, InputStream is) {


        File file = new File(filename);
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        byte[] bytes = new byte[1024*1024];
        int size = -1;
        while (true) {
           try{
               if(((size=is.read(bytes))>0)){
                   os.write(bytes,0,size);
               }else{
                   break;
               }
           }catch (IOException e){
               e.printStackTrace();
           }

        }


    }
    private boolean verifyPermissino(Activity activity){
        String[] PERMISSIONS_STORAGE = {
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE};
        int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if(permission!= PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this,PERMISSIONS_STORAGE,1);
        }
        return permission==PackageManager.PERMISSION_GRANTED;
    }
}

总结:
1.拷贝到本地存储起来并完成对本地视频文件的读写,需要完成权限的申请。manifest文件里还要申请权限就不列出来了。

2.使用systemvideoview或mediaplayer,直接利用文件的绝对路径也无法完成最后的播放,因为会抛出no contentProvider 的filenotfoundexception异常,所以笔者就采用了uri播放,但是常规的uri.parse是行不通的,还是会抛同样的异常,这里用了uri.fromFile就可以完美的规避这个异常。

3.如果在readSampleData中出了illegalArgumentException,记住,如果确认自己的参数类型没有丝毫问题,那么就可能出在bytebuffer的大小上,我第一次使用Input_max_size的常量作为buffer的大小,但是因为新版本问题,用不了。第二次随便申请了100kb的大小,之前只分离音频的时候还行,后面用到音视频的分离的时候就出错了。于是不得不直接申请两个1mb大小的buf去完成音视频数据的读写。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用以下步骤从mp4视频文件中提取帧缩略图: 1. 使用MediaExtractor从mp4文件中提取视频轨道数据。 ```java MediaExtractor extractor = new MediaExtractor(); extractor.setDataSource(filePath); int trackCount = extractor.getTrackCount(); for (int i = 0; i < trackCount; i++) { MediaFormat format = extractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); if (mime.startsWith("video/")) { extractor.selectTrack(i); ByteBuffer inputBuffer = ByteBuffer.allocate(1024 * 1024); MediaCodec codec = MediaCodec.createDecoderByType(mime); codec.configure(format, null, null, 0); codec.start(); boolean isEOS = false; while (!isEOS) { int sampleSize = extractor.readSampleData(inputBuffer, 0); if (sampleSize < 0) { isEOS = true; } else { long presentationTimeUs = extractor.getSampleTime(); codec.queueInputBuffer(inputBuffer.position(), sampleSize, presentationTimeUs, 0, isEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); extractor.advance(); } MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, TIMEOUT_US); while (outputBufferIndex >= 0) { Image image = codec.getOutputImage(outputBufferIndex); // 处理image,生成缩略图 codec.releaseOutputBuffer(outputBufferIndex, true); outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, TIMEOUT_US); } } codec.stop(); codec.release(); extractor.unselectTrack(i); } } extractor.release(); ``` 2. 使用MediaCodec进行视频解码,获取每一帧的Image对象。 3. 将Image对象转换为Bitmap对象,生成缩略图。 ```java Image.Plane[] planes = image.getPlanes(); ByteBuffer buffer = planes[0].getBuffer(); int pixelStride = planes[0].getPixelStride(); int rowStride = planes[0].getRowStride(); int rowPadding = rowStride - pixelStride * width; Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888); bitmap.copyPixelsFromBuffer(buffer); bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height); ``` 4. 可以使用OpenGL对缩略图进行后期处理,如旋转、缩放等操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值