Start processing data from pipe

ffmpeg is being weird. Wave files start with a header consisting of the
text "RIFF", followed by 4 bytes for the length of the data chunk. But
because we're streaming to a pipe, that value isn't known yet, so it
just fills in 0xFFFFFFFF. libsndfile apparently doesn't like this and
quits with the message "Error in WAV file. No 'data' chunk marker." I
think I might need to drop libsndfile and manually process the data.
This commit is contained in:
Brandon Skari
2017-05-10 17:47:28 -06:00
parent 6dfb5ba5b0
commit 8f25432e4f
2 changed files with 65 additions and 69 deletions

View File

@@ -8,6 +8,9 @@ import os
import subprocess
import threading
PIPE = 'pipe:1'
DUMMY_FILE = 'dummy-file'
def broadcast_fm(media_file_name, frequency):
"""Play a media file's audio over FM."""
@@ -29,36 +32,38 @@ def broadcast_fm(media_file_name, frequency):
VideoCodec = libavwrapper.VideoCodec
AudioCodec = libavwrapper.AudioCodec
Stream = libavwrapper.AVConv
Stream.add_option = Stream.add_parameter
command = 'avconv'
else:
raise NotImplementedError(
'Broadcasting audio requires either avconv or ffmpeg to be installed'
'Broadcasting audio requires either avconv or ffmpeg to be installed\n'
'sudo apt install libav-tools'
)
logger.debug('Using {}'.format(command))
logger.debug('Using %s', command)
pipe_name = '/tmp/rpitx-fifo.wav'
if not os.path.exists(pipe_name):
os.mkfifo(pipe_name)
input_media = Input(media_file_name)
codec = AudioCodec('pcm_s16le').frequence(48000).channels(1)
output_audio = Output(DUMMY_FILE, codec)
stream = Stream(command, input_media, output_audio)
command_line = list(stream)
# The format needs to be specified manually because we're writing to
# stderr and not a named file. Normally, it would infer the format from
# the file name extension. Also, ffmpeg will only write to a pipe if it's
# the last named argument.
command_line.remove(DUMMY_FILE)
command_line += ('-f', 'wav', PIPE)
logger.debug('Running command "%s"', ' '.join(command_line))
stream_process = subprocess.Popen(command_line, stdout=subprocess.PIPE)
def convert():
"""Runs the conversion command and writes to a FIFO."""
input_media = Input(media_file_name)
codec = AudioCodec('pcm_s16le').frequence(48000).channels(1)
output_audio = Output(pipe_name, codec)
stream = Stream(command, input_media, output_audio)
# Force overwriting existing file (it's a FIFO, that's what we want)
if hasattr(stream, 'add_option'):
stream.add_option('-y', '')
else:
stream.add_parameter('-y', '')
logger.debug(str(stream).replace("'", '').replace(',', ''))
def log_stdout():
"""Log stdout from the stream process."""
lines = stream.run()
for line in lines:
logger.debug(line)
thread = threading.Thread(target=convert)
thread.start()
#thread = threading.Thread(target=log_stdout).start()
logger.debug('Calling broadcast_fm')
_rpitx.broadcast_fm(pipe_name, frequency)
_rpitx.broadcast_fm(stream_process.stdout.fileno(), frequency)
thread.join()