Как уменьшить задержку потоковой передачи RTP с помощью ffmpeg в Android?

Я создаю приложение, которое выполняет потоковую передачу RTP. Он использует пару каналов ParcelFileDescriptor, где MediaRecorder записывает в канал, в то время как ffmpeg получает аудио из канала и отправляет по RTP.

На моем рабочем столе, используя тот же маршрутизатор Wi-Fi, я получаю поток RTP с помощью ffplay, и он имеет задержку между 5 и 10 с.

Я попытался захватить звук с помощью ffmpeg в Android, но это невозможно. Я пытался использовать ffplay -fflags nobuffer, использовать MIC в качестве источника, изменить кодировщик и т. Д.

Мне нужна минимальная возможная задержка. Как мне это сделать?

Код:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    MediaRecorder mediaRecorder;
    AudioRecord record;
    MediaPlayer mediaPlayer;
    ParcelFileDescriptor[] pipePair;
    ParcelFileDescriptor pipeRead;
    ParcelFileDescriptor pipeWrite;
    Process ffmpegProc;
    // Requesting permission to RECORD_AUDIO
    private boolean permissionsAccepted = false;
    private String [] permissions = {
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.INTERNET,
            Manifest.permission.ACCESS_NETWORK_STATE
    };
    private static final int REQUEST_PERMISSIONS = 200;

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case REQUEST_PERMISSIONS:
                permissionsAccepted  = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                break;
        }
        if (!permissionsAccepted ) finish();

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSIONS);

        TextView hello = (TextView) findViewById(R.id.hello);
        hello.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "Clicado",Toast.LENGTH_SHORT)
                        .show();
                copiarFFMpeg();

            }
        });

    }

    private void executarFFMpeg(final String[] cmd, ParcelFileDescriptor read) {

        try {
            ffmpegProc = Runtime.getRuntime().exec(cmd);
        } catch (IOException e) {
            e.printStackTrace();
        }

        (new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    InputStream inStream = ffmpegProc.getInputStream();
                    InputStreamReader sReader = new InputStreamReader(inStream);
                    BufferedReader bufferedReader = new BufferedReader(sReader);
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        Log.d("FFMPEG",line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        })).start();

        (new Thread(new Runnable() {
            @Override
            public void run() {
                byte[] buffer = new byte[8192];
                int read = 0;

                OutputStream ffmpegInput = ffmpegProc.getOutputStream();
                FileInputStream reader = new FileInputStream(pipeRead.getFileDescriptor());

                try {

                    while (true) {

                        if (reader.available()>0) {
                            read = reader.read(buffer);
                            ffmpegInput.write(buffer, 0, read);
                            ffmpegInput.flush();
                        } else {
                            Thread.sleep(10);
                        }

                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();

                } catch (IOException e) {
                    e.printStackTrace();

                    onDestroy();
                }
            }
        })).start();

        Log.d("FFMPEG","Executado");
    }

    private boolean estaExecutando(Process ffmpegProc) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return ffmpegProc.isAlive();
        } else {
            try {
                ffmpegProc.exitValue();
                return false;
            } catch (Exception e) {
                return true;
            }
        }
    }

    private void criarMediaRecorder() {
        if (pipeWrite != null) {
            try {
                //ffplay.exe -protocol_whitelist rtp,file,udp ..\file.sdp
                mediaRecorder = new MediaRecorder();
                mediaRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
                mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS);
                mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
                //mediaRecorder.setAudioChannels(2);
                mediaRecorder.setOutputFile(pipeWrite.getFileDescriptor());
                mediaRecorder.prepare();
                mediaRecorder.start();
                Log.d("MREC","MediaRecorder criado");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void criarPipe() {
        try {
            pipePair =ParcelFileDescriptor.createPipe();
        } catch (IOException e) {
            Log.e("PIPE","Deu zica na criação do pipe");
            e.printStackTrace();
            finish();
        }
        pipeRead = new ParcelFileDescriptor(pipePair[0]);
        pipeWrite  = new ParcelFileDescriptor(pipePair[1]);
    }

    private void copiarFFMpeg() {
        FFmpeg ffmpeg = FFmpeg.getInstance(this);
        try {
            ffmpeg.loadBinary(new LoadBinaryResponseHandler() {

                @Override
                public void onStart() {
                    Log.d("FFMPEG","Iniciar cópia");
                }

                @Override
                public void onFailure() {
                    Log.e("FFMPEG","Cópia falhou");
                }

                @Override
                public void onSuccess() {
                    Log.d("FFMPEG","Cópiado com sucesso");

                    criarPipe();
                    //mediaRecorder.start();
                    File ffmpegBin = new File(getFilesDir().getAbsolutePath()+"/ffmpeg");
                    String[] cmd = new String[] {
                            ffmpegBin.getAbsolutePath(),
                            "-re",
                            "-thread_queue_size","4",
                            "-i","pipe:",
                            //"-c:a","libx264",
                            //"-preset","veryfast",
                            //"-tune","zerolatency",
                            "-f",
                            "rtp",
                            "rtp://192.168.0.33:1234"
                    };

                    executarFFMpeg(cmd, pipeRead);

                    criarMediaRecorder();
                }

                @Override
                public void onFinish() {
                }
            });
        } catch (FFmpegNotSupportedException e) {
            // Handle if FFmpeg is not supported by device
            Log.e("FFMPEG", "Não sou suportado :/");
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onClick(View view) {

    }
}

Команда:

ffplay rtp://192.168.0.33:1234

ffplay -fflags nobuffer rtp://192.168.0.33:1234

0 ответов

Другие вопросы по тегам