писать с помощью PortAudio в fifo и читать с помощью ffmpeg на OSX

Что я пытаюсь сделать:

  1. открыть мой микрофон как источник звука в PortAudio (работает)
  2. записать поток в fifo (работает)
  3. читать fifo с помощью ffmpeg (не работает)

В PortAudio я использую блокирующий ввод-вывод, как здесь: http://portaudio.com/docs/v19-doxydocs/blocking_read_write.html

В цикле я пишу в fifo так:

int data = write('/tmp/aaa', sampleBlock, bufferSize);

когда я читаю его в буфер записи PortAudio, он работает.

bytes_read = read('/tmp/aaa', readSampleBlock, bufferSize);
err = Pa_WriteStream(stream, readSampleBlock, bufferSize)

когда я прочитал это с помощью ffmpeg на консоли:

ffmpeg -y -i /tmp/aaa -f s16le -acodec copy -f nut -ar 48000 -ac 2 -v debug -report -acodec copy out.wav

Он просто блокирует петлю и все.

Может ли кто-нибудь помочь мне понять, что мне нужно делать?

Мой код:

#define SAMPLE_SIZE (1)
#define FRAMES_PER_BUFFER (480)
#define AUDIOFIFO "/tmp/aaa"

char *sampleBlock = NULL;
int status, captured_bytes, fifo, bytes_read;


err = Pa_OpenStream(&stream,
                    &inputParameters,
                    NULL,
                    48000,
                    FRAMES_PER_BUFFER,
                    paClipOff,
                    NULL, /* no callback, use blocking API */
                    NULL ); /* no callback, so no callback userData */
if( err != paNoError ) goto error;

numBytes = FRAMES_PER_BUFFER * numChannels * SAMPLE_SIZE ;
sampleBlock = (char *) malloc( numBytes );
memset( sampleBlock, SAMPLE_SILENCE, numBytes );

if (status = mkfifo(AUDIOFIFO, 0666) < 0) 
{ 
  printf("Error making AUDIOFIFO: %s \n", strerror(errno)); 
}
err = Pa_StartStream( stream );
if( err != paNoError )
{
  goto error;
} 

fifo = open(AUDIOFIFO, O_RDWR, O_NONBLOCK);
if (fifo < 0) printf("Error opening AUDIOFIFO: %s \n", strerror(errno));

for( i=0; i<(60*48000)/FRAMES_PER_BUFFER; ++i )
{   
  if ((err = Pa_ReadStream(stream, sampleBlock, FRAMES_PER_BUFFER)) != paNoError)
  {
    goto xrun;
  }  
  captured_bytes = write(fifo, sampleBlock, FRAMES_PER_BUFFER);
  if (captured_bytes < 0) 
  { 
    printf("Error writing to AUDIOFIFO: %s \n", strerror(errno));
  }

  framesProcessed += bufferSize;
}

person M. P.    schedule 21.11.2017    source источник
comment
Попробуйте воспроизвести несколько секунд данных в fifo и просто прочитать их с помощью wc -c /tmp/aaa, и он скажет вам, сколько байтов ему удается прочитать. Если это кажется разумным, попробуйте еще раз, но на этот раз используйте cat /tmp/aaa > /tmp/data, а затем попробуйте запустить file /tmp/data, чтобы увидеть, можно ли идентифицировать его формат, и попробуйте xxd /tmp/data | more, чтобы увидеть, распознаете ли вы формат.   -  person Mark Setchell    schedule 21.11.2017
comment
он считывает точно размер буфера (8640 байт). file /tmp/data возвращает /tmp/data: data, а содержание доза мне мало что говорит, куча ругательств.   -  person M. P.    schedule 21.11.2017
comment
Каков размер /tmp/data?   -  person Mark Setchell    schedule 22.11.2017
comment
Я думаю, вам нужно опубликовать свой код... хотя бы минимальную, полную, проверяемую версию. Похоже, вы пишете только один буфер, который, скорее всего, зависнет ffmpeg.   -  person Mark Setchell    schedule 22.11.2017
comment
Я отредактировал вопрос с моим кодом. Когда я впервые открываю fifo с помощью cat /tmp/aaa > /tmp/data, а затем запускаю свое приложение, кошка читает гораздо больше данных, поэтому цикл работает и также не блокируется. Данные, которые я отправляю, просто не имеют смысла для ffmpeg.   -  person M. P.    schedule 22.11.2017
comment
Вы открыли его без блокировки.   -  person Mark Setchell    schedule 22.11.2017
comment
У меня сложилось впечатление, что когда я открываю его без блокировки, я могу просто начать отправлять туда что-то и беспокоиться о чтении. В любом случае, я пробовал оба, поведение одинаковое. Когда я запускаю свое приложение, а затем читаю с помощью cat, оно читает только первый буфер и выходит, когда я начинаю чтение с cat, а затем запускаю свое приложение, оно считывает все данные. Но данные не распознаются для ffmpeg.   -  person M. P.    schedule 22.11.2017
comment
Насколько я знаю, вы должны описать свой входной поток в ffmpeg перед его открытием, поэтому я думаю, что -f s16le по крайней мере должно быть перед -i /tmp/aaa в вашей командной строке ffmpeg.   -  person Mark Setchell    schedule 22.11.2017
comment
да .. вы можете опубликовать это как ответ, и я приму его.   -  person M. P.    schedule 22.11.2017
comment
Надеюсь, это означает, что вы в порядке? Если да, то круто - молодец и удачи вашему проекту.   -  person Mark Setchell    schedule 22.11.2017
comment
да, спасибо, звук немного забавный, но со временем я его пойму.   -  person M. P.    schedule 22.11.2017


Ответы (1)


Насколько я знаю, общий формат командной строки ffmpeg:

ffmpeg <GLOBAL OPTIONS> <INPUT OPTIONS> -i INPUT <OUTPUT OPTIONS> OUTPUT

т. е. вы должны описать свой входной поток в ffmpeg перед его открытием.

Поэтому я думаю, что -f s16le (по крайней мере) должно стоять перед -i /tmp/aaa в вашей командной строке ffmpeg:

ffmpeg -y -f s16le -i /tmp/aaa ....
person Mark Setchell    schedule 22.11.2017