MediaRecorder 没有第二次录制

Posted

技术标签:

【中文标题】MediaRecorder 没有第二次录制【英文标题】:MediaRecorder not recording the second time 【发布时间】:2020-04-01 16:36:00 【问题描述】:

我正在使用 MediaRecorder 记录用户屏幕。首次打开应用程序并且用户单击 fab 按钮记录屏幕时,一切正常。但是如果应用程序正在运行,用户再次单击记录按钮,在我想要的文件路径中不会生成新文件,因此我的列表视图不会更新。

如果我关闭该应用程序并再次运行该应用程序,则 mediarecorder 只能在第一次运行。我尝试了许多不同的方法,并在 Stack Overflow 上寻找解决方案,但都是徒劳的。第二次单击录制按钮时,我无法录制屏幕。我也没有收到任何错误。这是我的代码:

public class MainActivity extends AppCompatActivity 

private static final String TAG = "MainActivity";
private static final int DISPLAY_WIDTH = 720;
private static final int DISPLAY_HEIGHT = 1280;
Button btn;
private int screenDensity;
private MediaProjectionManager mediaProjectionManager;
private MediaProjection mediaProjection;
private VirtualDisplay virtualDisplay;
private MediaProjection.Callback mediaProjectionCallback;
private MediaRecorder mediaRecorder;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private boolean isRecording = false;
static SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss");
static String todayDate = dateFormat.format(new Date());

static 
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);


@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    String[] PERMISSIONS = Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO;

    if (!hasPermissions(this, PERMISSIONS)) 
        ActivityCompat.requestPermissions(this, PERMISSIONS, 1);
    

    DisplayMetrics displayMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    screenDensity = displayMetrics.densityDpi;

    mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);

    btn = findViewById(R.id.fab);
    btn.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
            toggleScreenShare();
        
    );


public static boolean hasPermissions(Context context, String... permissions) 
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) 
        for (String permission : permissions) 
            if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) 
                return false;
            
        
    
    return true;


public void recordBtnReload() 
    if (isRecording) 
        btn.setText("Stop");
     else 
        btn.setText("Record");
    


private void toggleScreenShare() 
    if (!isRecording) 
        initRecorder();
        shareScreen();
     else 
        mediaRecorder.stop();
        mediaRecorder.reset();
        mediaRecorder.release();
        mediaRecorder = null;
        stopScreenSharing();
    


private void stopScreenSharing() 
    if (virtualDisplay == null) 
        return;
    
    virtualDisplay.release();
    destroyMediaProjection();
    isRecording = false;
    recordBtnReload();


private void destroyMediaProjection() 
    if (mediaProjection != null) 
        mediaProjection.unregisterCallback(mediaProjectionCallback);
        mediaProjection.stop();
        mediaProjection = null;
    
    Log.i(TAG, "MediaProjection is stopped for now");


private void shareScreen() 
    if (mediaProjection == null) 
        startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 1000);
        return;
    
    virtualDisplay = createVirtualDisplay();
    mediaRecorder.start();
    isRecording = true;
    recordBtnReload();
    Log.i(TAG, "ShareScreen started for now");


private void initRecorder() 
    try 
        mediaRecorder = new MediaRecorder();
        mediaRecorder.setAudiosource(MediaRecorder.AudioSource.MIC);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

        mediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        mediaRecorder.setVideoEncodingBitRate(512 * 1000);
        mediaRecorder.setVideoFrameRate(16);
        mediaRecorder.setVideoEncodingBitRate(3000000);
        String directory = Environment.getExternalStorageDirectory() + File.separator + "NewCapture";
        File folder = new File(directory);
        boolean success = true;
        if (!folder.exists()) 
            success = folder.mkdir();
        
        String filepath;
        if (success) 
            String videoName = ("Video_" + todayDate + ".mp4");
            filepath = directory + File.separator + videoName;
            Log.i(TAG, "File created");
         else 
            Toast.makeText(this, "Failed to create Recordings directory", Toast.LENGTH_SHORT).show();
            return;
        
        mediaRecorder.setOutputFile(filepath);
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        int orientation = ORIENTATIONS.get(rotation + 90);
        mediaRecorder.setOrientationHint(orientation);
        mediaRecorder.prepare();
        Log.i(TAG, "initRecorder");
     catch (IOException e) 
        e.printStackTrace();
    


private VirtualDisplay createVirtualDisplay() 
    Log.i(TAG, "Created Virtual Display");
    return mediaProjection.createVirtualDisplay(TAG, DISPLAY_WIDTH, DISPLAY_HEIGHT, screenDensity,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mediaRecorder.getSurface(), null, null);


@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) 
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode != 1000) 
        Log.e(TAG, "Unknown request code:" + requestCode);
        return;
    
    if (resultCode != RESULT_OK) 
        Toast.makeText(this, "Permission for screen recording is denied", Toast.LENGTH_LONG).show();
        isRecording = false;
        recordBtnReload();
        return;
    
    mediaProjectionCallback = new MediaProjection.Callback() 
        @Override
        public void onStop() 
            if (isRecording) 
                isRecording = false;
                recordBtnReload();
                mediaRecorder.stop();
                mediaRecorder.reset();
                mediaRecorder.release();
                mediaRecorder = null;
            
            mediaProjection = null;
            stopScreenSharing();
        
    ;

    mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
    mediaProjection.registerCallback(mediaProjectionCallback, null);
    virtualDisplay = createVirtualDisplay();
    mediaRecorder.start();
    isRecording = true;
    recordBtnReload();


@Override
protected void onDestroy() 
    super.onDestroy();
    destroyMediaProjection();

我不知道我做错了什么。我还在学习应用程序开发。

【问题讨论】:

您能否提供一个简化示例的完整代码?例如,您可以去掉适配器并只记录 getData() 的结果。目前,当我将您提供的代码复制到一个活动中时,它远非可运行。如果不先做很多工作,我就帮不了你,这会降低你得到答案的可能性。查看***.com/help/minimal-reproducible-example @Michiyo 我在我的问题中编辑了我的代码。现在,它只有 mediarecorder 功能并将录制的视频保存到存储中。如果您将代码复制到活动中并在清单中添加相关权限,则应用程序应该会运行。请检查您的文件目录以获取录制的文件。您会注意到即使您录制了多次,也只会创建一个文件。我必须终止该应用程序并重新启动才能创建新的录制文件。 【参考方案1】:

我的代码中的问题在于 initRecorder() 函数。而不是使用以下代码来创建文件名:

String videoName = ("Video_" + todayDate + ".mp4");

其中,todayDate 是一个日期格式化程序。我用以下代码替换了代码:

String videoName = ("Video_" + System.currentTimeMillis() + ".mp4");

这需要当前系统时间并在文件名中分配它。现在新文件已创建,我不必每次都重新启动应用程序来记录新文件。

【讨论】:

以上是关于MediaRecorder 没有第二次录制的主要内容,如果未能解决你的问题,请参考以下文章

MediaRecorder 录制开始时静音(延迟?)

mediarecorder 如何暂停和恢复录制视频

通过 MediaRecorder 录制音频

如何使用 MediaRecorder 获取录制声音的每个频率?

Android:使用 MediaRecorder 录制音频 - 文件不播放

在 Android 中使用 AudioRecorder/MediaRecorder 录制 FLAC 音频