Saving a stream while playing it using LibVLC - c++

Using LibVLC, I'm trying to save a stream while playing it. This is the python code:
import os
import sys
import vlc
if __name__ == '__main__':
filepath = <either-some-url-or-local-path>
movie = os.path.expanduser(filepath)
if 'http://' not in filepath:
if not os.access(movie, os.R_OK):
print ( 'Error: %s file is not readable' % movie )
sys.exit(1)
instance = vlc.Instance("--sub-source marq --sout=file/ps:example.mpg")
try:
media = instance.media_new(movie)
except NameError:
print ('NameError: % (%s vs Libvlc %s)' % (sys.exc_info()[1],
vlc.__version__, vlc.libvlc_get_version()))
sys.exit(1)
player = instance.media_player_new()
player.set_media(media)
player.play()
#dont exit!
while(1):
continue
It saves the video stream to a file example.mpg. As per this doc, the command to save a stream is this :
--sout=file/ps:example.mpg
which I've using when creating an instance of vlc.Instance:
instance = vlc.Instance("--sub-source marq --sout=file/ps:example.mpg")
But the problem is that it only saves the stream, it doesn't play the stream simultaneously.
Is there any way (in LibVLC) I can save the stream (to a local file) while paying it?
Although, I'm looking for a solution in Python 3.3.1 but it is fine if there is any C or C++ solution.
I've created a similar, but not duplicate, topic yesterday.

Idea:
The basic idea is simple enough. You have to duplicate the output stream and redirect it to a file. This is done, as Maresh correctly pointed out, using the sout=#duplicate{...} directive.
Working Solution:
The following solution works on my machine ™. I've tested it on Ubuntu 12.10 with VLC v2.0.3 (TwoFlower) and Python 2.7.1. I think it should also work on Python 3 since most of the heavy lifting is done by libVlc anyway.
import os
import sys
import vlc
if __name__ == '__main__':
#filepath = <either-some-url-or-local-path>
movie = os.path.expanduser(filepath)
if 'http://' not in filepath:
if not os.access(movie, os.R_OK):
print ( 'Error: %s file is not readable' % movie )
sys.exit(1)
instance = vlc.Instance("--sout=#duplicate{dst=file{dst=example.mpg},dst=display}")
try:
media = instance.media_new(movie)
except NameError:
print ('NameError: % (%s vs Libvlc %s)' % (sys.exc_info()[1],
vlc.__version__, vlc.libvlc_get_version()))
sys.exit(1)
player = instance.media_player_new()
player.set_media(media)
player.play()
#dont exit!
while(1):
continue
Helpful Links
The Command-Line help was essential to decipher the plethora of VLCs
command line options.
Chapter 3 of VLC streaming HowTo. Explains the structure of the stream output, its directives and describes of the various available modules. Chapter 4 shows some examples.
LibVLC API documentation in case you want to change media option at
runtime
Update - Saving YouTube videos:
The above code doesn't play nice with YouTube. I searched around and discovered that an additional transcode directive can be used to convert YouTube's video stream to a regular video format. I used #transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128,deinterlace}
vcodec=mp4v is the video format you want to encode in (mp4v is MPEG-4, mpgv is MPEG-1, and there is also h263, DIV1, DIV2, DIV3, I420, I422, I444, RV24, YUY2).
acodec=mpga is the audio format you want to encode in (mpga is MPEG audio layer 2, a52 is A52 i.e. AC3 sound).
vb=800 is the video bitrate in Kbit/s.
ab=128 is the audio bitrate in Kbit/s.
deinterlace tells VLC to deinterlace the video on the fly.
The updated code looks like this:
import os
import sys
import vlc
if __name__ == '__main__':
#filepath = <either-some-url-or-local-path>
filepath = "http://r1---sn-nfpnnjvh-1gil.c.youtube.com/videoplayback?source=youtube&newshard=yes&fexp=936100%2C906397%2C928201%2C929117%2C929123%2C929121%2C929915%2C929906%2C929907%2C929125%2C929127%2C925714%2C929917%2C929919%2C912512%2C912515%2C912521%2C906838%2C904485%2C906840%2C931913%2C904830%2C919373%2C933701%2C904122%2C932216%2C936303%2C909421%2C912711%2C907228%2C935000&sver=3&expire=1373237257&mt=1373214031&mv=m&ratebypass=yes&id=1907b7271247a714&ms=au&ipbits=48&sparams=cp%2Cid%2Cip%2Cipbits%2Citag%2Cratebypass%2Csource%2Cupn%2Cexpire&itag=45&key=yt1&ip=2a02%3A120b%3Ac3c6%3A7190%3A6823%3Af2d%3A732c%3A3577&upn=z3zzcrvPC0U&cp=U0hWSFJOVV9KUUNONl9KSFlDOmt4Y3dEWFo3dDFu&signature=D6049FD7CD5FBD2CC6CD4D60411EE492AA0E9A77.5D0562CCF4E10A6CC53B62AAFFF6CB3BB0BA91C0"
movie = os.path.expanduser(filepath)
savedcopy = "yt-stream.mpg"
if 'http://' not in filepath:
if not os.access(movie, os.R_OK):
print ( 'Error: %s file is not readable' % movie )
sys.exit(1)
instance = vlc.Instance("--sout=#transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128,deinterlace}:duplicate{dst=file{dst=%s},dst=display}" % savedcopy)
try:
media = instance.media_new(movie)
except NameError:
print ('NameError: % (%s vs Libvlc %s)' % (sys.exc_info()[1],
vlc.__version__, vlc.libvlc_get_version()))
sys.exit(1)
player = instance.media_player_new()
player.set_media(media)
player.play()
#dont exit!
while(1):
continue
A couple of important points:
I've used MPEG audio and video codecs in the transcode directive. It seems to be important to use a matching extensions for the output file (mpg in this case). Otherwise VLC gets confused when opening the saved file for playback. Keep that in mind if you decide to switch to another video format.
You cannot add a regular YouTube URL as filepath. Instead you have to specify the location of the video itself. That's the reason why the filepath that I've used looks so cryptic. That filepath corresponds to video at http://www.youtube.com/watch?v=GQe3JxJHpxQ. VLC itself is able to extract the video location from a given YouTube URL, but libVLC doesn't do that out of the box. You'll have to write your own resolver to do that. See this related SO question. I followed this approach to manually resolve the video location for my tests.

I think you need to duplicate the output in order to play and record it at the same time:
vlc.Instance("--sub-source marq --sout=#stream_out_duplicate{dst=display,dst=std{access=file,mux=ts,dst=/path/file.mpg}}")
or
libvlc_media_add_option(media, ":sout=#stream_out_duplicate{dst=display,dst=std{access=file,mux=ts,dst=/path/file.mpg}}")

Did you try adding to the list of options the following option?
--sout-display
i.e.
instance = vlc.Instance("--sub-source marq --sout=file/ps:example.mpg --sout-display")

Some time ago in a sample code in the active state website i saw someone played and recorded a MP3 file using VLC using the vlc.py module. You can take a look at it's sample code to see how to duplicate a stream. I copied th code here for you (I copied it from http://code.activestate.com/recipes/577802-using-vlcpy-to-record-an-mp3-and-save-a-cue-file/):
import vlc
import time
import os
def new_filename(ext = '.mp3'):
"find a free filename in 00000000..99999999"
D = set(x[:8] for x in os.listdir('.')
if (x.endswith(ext) or x.endswith('.cue')) and len(x) == 12)
for i in xrange(10**8):
s = "%08i" %i
if s not in D:
return s
def initialize_cue_file(name,instream,audiofile):
"create a cue file and write some data, then return it"
cueout = '%s.cue' %name
outf = file(cueout,'w')
outf.write('PERFORMER "%s"\n' %instream)
outf.write('TITLE "%s"\n' %name)
outf.write('FILE "%s" WAVE\n' %audiofile)
outf.flush()
return outf
def initialize_player(instream, audiofile):
"initialize a vlc player which plays locally and saves to an mp3file"
inst = vlc.Instance()
p = inst.media_player_new()
cmd1 = "sout=#duplicate{dst=file{dst=%s},dst=display}" %audiofile
cmd2 ="no-sout-rtp-sap"
cmd3 = "no-sout-standard-sap"
cmd4 ="sout-keep"
med=inst.media_new(instream,cmd1,cmd2,cmd3,cmd4)
med.get_mrl()
p.set_media(med)
return p, med
def write_track_meta_to_cuefile(outf,instream,idx,meta,millisecs):
"write the next track info to the cue file"
outf.write(' TRACK %02i AUDIO\n' %idx)
outf.write(' TITLE "%s"\n' %meta)
outf.write(' PERFORMER "%s"\n' %instream)
m = millisecs // 60000
s = (millisecs - (m*60000)) // 1000
hs = (millisecs - (m*60000) - (s*1000)) //10
ts = '%02i:%02i:%02i' %(m,s,hs)
outf.write(' INDEX 01 %s\n' %ts)
outf.flush()
def test():
#some online audio stream for which this currently works ....
instream = 'http://streamer-mtc-aa05.somafm.com:80/stream/1018'
#if the output filename ends with mp3 vlc knows which mux to use
ext = '.mp3'
name = new_filename(ext)
audiofile = '%s%s' %(name,ext)
outf = initialize_cue_file(name,instream,audiofile)
p,med = initialize_player(instream, audiofile)
p.play()
np = None
i = 0
while 1:
time.sleep(.1)
new = med.get_meta(12)
if new != np:
i +=1
t = p.get_time()
print "millisecs: %i" %t
write_track_meta_to_cuefile(outf,instream,i,new,t)
np = new
print "now playing: %s" %np
if __name__=='__main__':
test()

Perhaps you need to clone your output, as suggested on the forum?

Related

How to put and access a file with FFmpeg in Google Cloude Storages?

Hi I am a novice developer and deployed my first django project on Heroku.
I want to compress it into ffmpeg and save it to Google Cloud Storage when the user uploads a video file from uploadForm in the Django project.And by extracting the duration from the saved video using ffprobe and storing it in the duration field of object.
Save() of My forms.py code is as follows:
def save(self, *args, **kwargs):
def clean_video(self):
raw_video = self.cleaned_data.get("video")
timestamp = int(time())
raw_video_path = raw_video.temporary_file_path()
print(raw_video_path)
video_name = f"{raw_video}".split(".")[0]
subprocess.run(f"ffmpeg -i {raw_video_path} -vcodec libx265 -crf 28 -acodec mp3 -y uploads/videoart_files/{video_name}_{timestamp}.mp4", shell=True)
return f"videoart_files/{video_name}_{timestamp}.mp4"
videoart = super().save(commit=False)
videoart.video = clean_video(self)
video_path = videoart.video.path
get_duration = subprocess.check_output(['ffprobe', '-i', f'{video_path}', '-show_entries', 'format=duration', '-v', 'quiet', '-of', 'csv=%s' % ("p=0")])
duration = int(float(get_duration.decode('utf-8').replace("\n", "")))
videoart.duration = duration
return videoart
After all the validation of the other fields, I put the code to process the video inside the save method to compress the video at the end. Anyway, this code is not a problem in the local server it works very well. However, the server gets a NotImplementedError ("This backend dogn't support absolute paths.") error.
Naturally, ffmpeg can receive input videos from temporary_file_path(), but it doesn't find a path to output. This absolute path is not the path of GCS.
However, ffmpeg will not recognize the url. I'm not sure how to save a file created in ffmpeg on the server to GCS and how to access it.
Don't you want to give me some advice?

Google Cloud's rate and pitch prosody attributes

I am new to Google Cloud's Text-to-speech. The docs show the <prosody> tag with rate and pitch attributes. But these do not make a difference in my requests. For example, if I use rate="slow" or rate="fast", or pitch="+2st" or pitch="-2st", the result is the same and different from the example on the docs, which has a slower rate and lower tone.
I ensured the latest version with:
python3 -m pip install --upgrade google-cloud-texttospeech
Minimal reproducible example:
import os
from google.cloud import texttospeech
AUDIO_CONFIG = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.LINEAR16)
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "/path/to/file"
tts_client = texttospeech.TextToSpeechClient()
voice = texttospeech.VoiceSelectionParams(
language_code="en-US",
name= "en-US-Wavenet-A"
)
ssml_input = texttospeech.SynthesisInput(
ssml='<prosody rate="fast" pitch="+2st">Can you hear me now?</prosody>'
# or this one:
#ssml='<prosody rate="slow" pitch="-2st">Can you hear me now?</prosody>'
)
response = tts_client.synthesize_speech(
input=ssml_input, voice=voice, audio_config=AUDIO_CONFIG
)
with open("/tmp/cloud.wav", 'wb') as out:
# Write the response to the output file.
out.write(response.audio_content)
How can I use Google Cloud's rate and pitch prosody attributes?
According to this document, when you are writing a SSML script inside Text-to-Speech code, the format for the SSML script should be like :
<speak>
<prosody rate="slow" pitch="low">Hi good morning have a nice day</prosody>
</speak>
You can refer to the below mentioned piece of code, I tried at my end and it is working for me.
Code 1 :
I used pitch as low and rate as slow .
from google.cloud import texttospeech
client = texttospeech.TextToSpeechClient()
# Sets the text input to be synthesized
synthesis_input = texttospeech.SynthesisInput(
ssml= '<speak><prosody rate="slow" pitch="low">Hi good morning have a nice day</prosody></speak>'
)
# Builds the voice request, selects the language code ("en-US") and
# the SSML voice gender ("MALE")
voice = texttospeech.VoiceSelectionParams(
language_code="en-US", ssml_gender=texttospeech.SsmlVoiceGender.MALE
)
# Selects the type of audio file to return
audio_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.MP3
)
# Performs the text-to-speech request on the text input with the selected
# voice parameters and audio file type
response = client.synthesize_speech(
input=synthesis_input, voice=voice, audio_config=audio_config
)
# Writes the synthetic audio to the output file.
with open("output.mp3", "wb") as out:
# Write the response to the output file.
out.write(response.audio_content)
print('Audio content written to file "output.mp3"')
Audio output : output audio
Code 2 :
I used a rate as fast and pitch as +5st.
from google.cloud import texttospeech
client = texttospeech.TextToSpeechClient()
# Sets the text input to be synthesized
synthesis_input = texttospeech.SynthesisInput(
ssml= '<speak><prosody rate="fast" pitch="+5st">Hi good morning have a nice day</prosody></speak>'
)
# Builds the voice request, selects the language code ("en-US") and
# the SSML voice gender ("MALE")
voice = texttospeech.VoiceSelectionParams(
language_code="en-US", ssml_gender=texttospeech.SsmlVoiceGender.MALE
)
# Selects the type of audio file to return
audio_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.MP3
)
# Performs the text-to-speech request on the text input with the selected
# voice parameters and audio file type
response = client.synthesize_speech(
input=synthesis_input, voice=voice, audio_config=audio_config
)
# Writes the synthetic audio to the output file.
with open("output.mp3", "wb") as out:
# Write the response to the output file.
out.write(response.audio_content)
print('Audio content written to file "output.mp3"')
Audio output : output audio

How can I conver a transcribed .wav into txt in full extent. - Google Speech API

I'm having trouble with converting full transcribed speech to a text file. Eventually, I get what I need but not the entire text from the audio file. Let me note this (1 Pic), I can see the whole text when I use print() function but get only one line of that text when I try to write it to .txt file (2 Pic).
Also, you can look at my code if you need additional info and stuff. Thank you in advance!
from google.cloud import speech
import os
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'PATH'
client = speech.SpeechClient()
with open('sample.wav', "rb") as audio_file:
content = audio_file.read()
audio = speech.RecognitionAudio(content=content)
config = speech.RecognitionConfig(
encoding=speech.RecognitionConfig.AudioEncoding.LINEAR16,
sample_rate_hertz=8000,
language_code="en-US",
# Enable automatic punctuation
enable_automatic_punctuation=True,
)
response = client.recognize(config=config, audio=audio)
for result in response.results:
extr = result.alternatives[0].transcript
print(extr)
with open("guru9.txt","w+") as f:
f.write(extr)
f.close()
What happens in your code is, per iteration you open, write, close your file. You should move out your opening and closing of your file outside the loop.
myfile = open("guru9.txt","w+")
for result in response.results:
extr = result.alternatives[0].transcript
myfile.write(extr)
myfile.close()

How do I use the same data to create multiple files?

I am trying to create two files with the same data. One file to use for updating live web data and the other as a log. One file needs to be appended to and updated frequently. I can create the log fine but am struggling on how to handle the data for the second file.
I have tried using a 'with open' statement for the log file. When I try reading this into a live web page, it shows me the data that has been logged previously, and updates the data only when the file is closed.
#!/usr/bin/env python2.7
import os
import RPi.GPIO as GPIO
import time
import subprocess
#Solar Panel Script 1.0
#Set pin for Pump Relay Signal (PR = pin 29)
#Set up Pump Relay BCM5 (pin 29) as output pin in off position
GPIO.setmode(GPIO.BCM)
GPIO.setup (5, GPIO.OUT, initial=0)
GPIO.setwarnings(False)
#Load Hot Water Tank (HWT), Solar Panel (SP), and Outside Temp (OT) with OWFS
#Create CSV File for temperature data
from time import sleep, strftime, time
with open("/var/www/html/data.csv", "a") as log:
while True:
with open ("/mnt/1wire/28.C14777910F02/temperature", "r") as myfile:
HWT=myfile.read().replace('\n', '')
myfile.close()
with open ("/mnt/1wire/28.390877910402/temperature", "r") as myfile2:
SP=myfile2.read().replace('\n', '')
myfile.close()
log.write("{0},{1},{2}\n".format(strftime("%Y-%m-%d %H:%M:%S"), str(HWT), str(SP)))
#Solar Hot Water Heater Module
#Turns on PR only if SP is 10F hotter than HWT. Checks OT for frezing temps, if less than 33, PR is off.
print ('hot water: ' + HWT)
print ('solar panel: '+ SP)
flt_HWT = float(HWT)
flt_SP = float(SP)
if flt_HWT > 170:
GPIO.output(5, GPIO.LOW) #Pump Relay Off
if flt_SP > (flt_HWT + 10):
GPIO.output(5, GPIO.HIGH) #Pump Relay On
state = GPIO.input(5)
print state
sleep(20) #10 Minutes = 600
I expected the log file to allow me to collect data from it while it was open.
log.write("{0},{1},{2}\n".format(strftime("%Y-%m-%d %H:%M:%S"), str(HWT), str(SP)))
This is where you are writing the log. You can simply include another with open() statement here
with open("secondfile.log") as secfile:
log.write("{0},{1},{2}\n".format(strftime("%Y-%m-%d %H:%M:%S"), str(HWT), str(SP))) ##original log file can be here
secfile.write("{0},{1},{2}\n".format(strftime("%Y-%m-%d %H:%M:%S"), str(HWT), str(SP))) ##and here you are wrighting the second file.
However if you are wrighting multiple files it would be better to stick them into a function of their own.
def write_file(text, filename):
try:
with open(filename) as file:
file.write(text)
return True
except:
return False ##include any other exception stuff here
now you can use
success = write_file("log text", "filename.log")
if success:
success = write_file("log2 text", "filename2.log")
if success:
print("Yey both files have been written to")
else:
print("Awww, there was an error writing to the file")

converting tiff to jpeg in python

Can anyone help me to read .tiff image and convert into jpeg format?
from PIL import Image
im = Image.open('test.tiff')
im.save('test.jpeg')
The above code was not working.
I have successfully solved the issue. I posted the code to read the tiff files in a folder and convert into jpeg automatically.
import os
from PIL import Image
yourpath = os.getcwd()
for root, dirs, files in os.walk(yourpath, topdown=False):
for name in files:
print(os.path.join(root, name))
if os.path.splitext(os.path.join(root, name))[1].lower() == ".tiff":
if os.path.isfile(os.path.splitext(os.path.join(root, name))[0] + ".jpg"):
print "A jpeg file already exists for %s" % name
# If a jpeg is *NOT* present, create one from the tiff.
else:
outfile = os.path.splitext(os.path.join(root, name))[0] + ".jpg"
try:
im = Image.open(os.path.join(root, name))
print "Generating jpeg for %s" % name
im.thumbnail(im.size)
im.save(outfile, "JPEG", quality=100)
except Exception, e:
print e
import os, sys
from PIL import Image
I tried to save directly to jpeg but the error indicated that the mode was P and uncompatible with JPEG format so you have to convert it to RGB mode as follow.
for infile in os.listdir("./"):
print "file : " + infile
if infile[-3:] == "tif" or infile[-3:] == "bmp" :
# print "is tif or bmp"
outfile = infile[:-3] + "jpeg"
im = Image.open(infile)
print "new filename : " + outfile
out = im.convert("RGB")
out.save(outfile, "JPEG", quality=90)
This can be solved with the help of OpenCV. It worked for me.
OpenCV version == 4.3.0
import cv2, os
base_path = "data/images/"
new_path = "data/ims/"
for infile in os.listdir(base_path):
print ("file : " + infile)
read = cv2.imread(base_path + infile)
outfile = infile.split('.')[0] + '.jpg'
cv2.imwrite(new_path+outfile,read,[int(cv2.IMWRITE_JPEG_QUALITY), 200])
I believe all the answers are not complete
TIFF image format is a container for various formats. It can contain BMP, TIFF noncompressed, LZW compressions, Zip compressions and some others, among them JPG etc.
image.read (from PIL) opens these files but cant't do anything with them. At least you can find out that it is a TIFF file (inside, not only by its name). Then one can use
pytiff.Tiff (from pytiff package). For some reasons, when tiff has JPG compression (probably, some others too) it cannot encode the correct information.
Something is rotten in the state of Denmark (C)
P.S. One can convert file with help of Paint (in old windows Paint Brush (Something is rotten in this state too) or Photoshop - any version. Then it can be opened from PythonI'm looking for simple exe which can do it, the call it from python. Probably Bulk Image Converter will do
I liked the solution suggested in this answer: https://stackoverflow.com/a/28872806/12808155
But checking for tiff in my opinion is not entirely correct, since there may be situations when the extension .tif does not define the file format: for example, when indexing, macOS creates hidden files ( ._DSC_123.tif).
For a more universal solution, I suggest using the python-magic library (https://pypi.org/project/python-magic)
The code for checking for tiff format may look like this:
import magic
def check_is_tif(filepath: str) -> bool:
allowed_types = [
'image/tiff',
'image/tif'
]
if magic.from_file(filepath, mime=True) not in allowed_types:
return False
return True
Complete code may looks like this:
import argparse
import os
import magic
from PIL import Image
from tqdm import tqdm
def check_is_tif(filepath: str) -> bool:
allowed_types = [
'image/tiff',
'image/tif'
]
if magic.from_file(filepath, mime=True) not in allowed_types:
return False
return True
def count_total(path: str) -> int:
print('Please wait till total files are counted...')
result = 0
for root, _, files in os.walk(path):
for name in files:
if check_is_tif(os.path.join(root, name)) is True:
result += 1
return result
def convert(path) -> None:
progress = tqdm(total=count_total(path))
for root, _, files in os.walk(path):
for name in files:
if check_is_tif(os.path.join(root, name)) is True:
file_path = os.path.join(root, name)
outfile = os.path.splitext(file_path)[0] + ".jpg"
try:
im = Image.open(file_path)
im.thumbnail(im.size)
im.save(outfile, "JPEG", quality=80)
os.unlink(file_path)
except Exception as e:
print(e)
progress.update()
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Recursive TIFF to JPEG converter')
parser.add_argument('path', type=str, help='Path do directory with TIFF files')
args = parser.parse_args()
convert(args.path)