I am looking for a way to save the current frame, from a specified live Twitch.tv channel, to disk. Any programming language is welcomed.
So far I've found a possible solution using Python here but unfortunately it doesn't work.
import time, Image
import cv2
from livestreamer import Livestreamer
# change to a stream that is actually online
livestreamer = Livestreamer()
plugin = livestreamer.resolve_url("http://twitch.tv/flosd")
streams = plugin.get_streams()
stream = streams['best']
# download enough data to make sure the first frame is there
fd = stream.open()
data = ''
while len(data) < 3e5:
data += fd.read()
time.sleep(0.1)
fd.close()
fname = 'stream.bin'
open(fname, 'wb').write(data)
capture = cv2.VideoCapture(fname)
imgdata = capture.read()[1]
imgdata = imgdata[...,::-1] # BGR -> RGB
img = Image.fromarray(imgdata)
img.save('frame.png')
Apparently cv2.VideoCapture(fname) returns none although it managed to write about 300K of information to stream.bin
Related
Hey guys I programmatically created a video using Moviepy and Gizeh. Right now it saves the final video as a mp4 file.
Is it possible to upload that video frame by frame to youtube (livestream) without saving it on my computer ?
Hi thanks for posting the question. Yes, it is possible! Since you specifically mentioned Youtube I would refer to these two references:
PYTHON FFMPEG VIDEO STREAMING DOCS
Delivering Live YouTube Content via Dash
I wish all the best. Do write if you have more questions
You can use VidGear Library's WriteGear API with its FFmpeg backend which can easily upload any live video frame by frame to YouTube (livestream) over RTMP protocol in few lines of python code as follows:
Without Audio
# import required libraries
from vidgear.gears import CamGear
from vidgear.gears import WriteGear
import cv2
# define and open video source
stream = CamGear(source="/home/foo/foo.mp4", logging=True).start()
# define required FFmpeg parameters for your writer
output_params = {
"-clones": ["-f", "lavfi", "-i", "anullsrc"],
"-vcodec": "libx264",
"-preset": "medium",
"-b:v": "4500k",
"-bufsize": "512k",
"-pix_fmt": "yuv420p",
"-f": "flv",
}
# [WARNING] Change your YouTube-Live Stream Key here:
YOUTUBE_STREAM_KEY = "xxxx-xxxx-xxxx-xxxx-xxxx"
# Define writer with defined parameters
writer = WriteGear(
output_filename="rtmp://a.rtmp.youtube.com/live2/{}".format(YOUTUBE_STREAM_KEY),
logging=True,
**output_params
)
# loop over
while True:
# read frames from stream
frame = stream.read()
# check for frame if Nonetype
if frame is None:
break
# {do something with the frame here}
# write frame to writer
writer.write(frame)
# safely close video stream
stream.stop()
# safely close writer
writer.close()
With Audio
# import required libraries
from vidgear.gears import CamGear
from vidgear.gears import WriteGear
import cv2
# define video source
VIDEO_SOURCE = "/home/foo/foo.mp4"
# Open stream
stream = CamGear(source=VIDEO_SOURCE, logging=True).start()
# define required FFmpeg optimizing parameters for your writer
# [NOTE]: Added VIDEO_SOURCE as audio-source
# [WARNING]: VIDEO_SOURCE must contain audio
output_params = {
"-i": VIDEO_SOURCE,
"-acodec": "aac",
"-ar": 44100,
"-b:a": 712000,
"-vcodec": "libx264",
"-preset": "medium",
"-b:v": "4500k",
"-bufsize": "512k",
"-pix_fmt": "yuv420p",
"-f": "flv",
}
# [WARNING]: Change your YouTube-Live Stream Key here:
YOUTUBE_STREAM_KEY = "xxxx-xxxx-xxxx-xxxx-xxxx"
# Define writer with defined parameters and
writer = WriteGear(
output_filename="rtmp://a.rtmp.youtube.com/live2/{}".format(YOUTUBE_STREAM_KEY),
logging=True,
**output_params
)
# loop over
while True:
# read frames from stream
frame = stream.read()
# check for frame if Nonetype
if frame is None:
break
# {do something with the frame here}
# write frame to writer
writer.write(frame)
# safely close video stream
stream.stop()
# safely close writer
writer.close()
Reference: https://abhitronix.github.io/vidgear/latest/help/writegear_ex/#using-writegears-compression-mode-for-youtube-live-streaming
I'm getting the error below when reading HLS(HTTP Live Streaming) segment files to OpenCV, using cv2.VideoCapture()
[mov,mp4,m4a,3gp,3g2,mj2 # 0x7f941f2ca200] could not find corresponding trex
[mov,mp4,m4a,3gp,3g2,mj2 # 0x7f941f2ca200] error reading header
The segment files are mp4 and HLS server is Amazon Kinesis Video Stream. The error message says that I'm missing header part of mp4 and it looks somehow reasonable because HLS provides a sequence of files.
My question here is, reading HLS segments to OpenCV is totally wrong approach? or we have some workaround?
import boto3
import cv2
import requests
import re
kinesis_client = boto3.client('kinesisvideo',
region_name='ap-northeast-1'
)
endpoint = kinesis_client.get_data_endpoint(
StreamARN='MY_ARN',
APIName='GET_HLS_STREAMING_SESSION_URL'
)
data_endpoint = endpoint['DataEndpoint']
url_prefix = data_endpoint + "/hls/v1/"
video_client = boto3.client('kinesis-video-archived-media',
endpoint_url=data_endpoint
)
# Retrieve HLS manifest URL from Kinesis Video Stream
session_url = video_client.get_hls_streaming_session_url(
StreamARN='MY_ARN',
HLSFragmentSelector={'FragmentSelectorType': 'PRODUCER_TIMESTAMP'}
)
session_url = session_url['HLSStreamingSessionURL']
# Fetch segment(mp4) file urls
master_playlist = requests.get(session_url)
media_playlist_url = url_prefix + master_playlist.text.split("\n")[-2]
media_playlist = requests.get(media_playlist_url)
media_playlist = media_playlist.text
pattern = r"getMP4Media"
segments = filter(lambda x: re.match(pattern,x), media_playlist.split("\n"))
for segment in segments:
segment_url = url_prefix + segment
# Debug segment url
# This emits something like: https://b-87178fb5.kinesisvideo.ap-northeast-1.amazonaws.com/hls/v1/getMP4MediaFragment.mp4?FragmentNumber=91343852333186478711651164912799448912305946338&SessionToken=CiAFReSdi9NKKz8vDum-Bs_8MFJ-5jIk06WmiyKDQQazihIQLdLPLuvr6scwc4HhAo6uDRoZWbgLHyJK01pTzFujc-cSkfl0oo4pIFD2sSIghdfInJL4XqMc_brBoLCikS73I3Nxxxxxxxxxxx
print(segment_url)
# Read mp4 file from Kinesis Video Sterams
cap = cv2.VideoCapture(segment_url)
while(cap.isOpened()):
ret, frame = cap.read()
cv2.imshow("Frame",frame)
cap.release()
I have a Binary string of mp4 video file and want to convert it back to mp4 file, to get single frame out of there with openCV library
import cv2
import tempfile
temp_path = tempfile.gettempdir()
video_binary_string = 'AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAQC0ttZGF0AQIUGRQmM...'
with open(temp_path+'/video.mp4', 'wb') as wfile:
wfile.write(video_binary_string)
cap = cv2.VideoCapture(temp_path+'/video.mp4')
success, frame = cap.read()
print success
>>> False
If frame was read correctly, it would be True
I understand that this is not the correct way of writing video file. I tried to do it with FFMPEG but I can't understand it's documentation.
Please give an example with simple explanations how to convert binary string back to video, with this or other way.
The solution for my problem is that I have to first decode encoded string
import cv2
import tempfile
import base64
temp_path = tempfile.gettempdir()
video_binary_string = 'AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAQC0ttZGF0AQIUGRQmM...'
decoded_string = base64.b64decode(video_binary_string)
with open(temp_path+'/video.mp4', 'wb') as wfile:
wfile.write(decoded_string)
cap = cv2.VideoCapture(temp_path+'/video.mp4')
success, frame = cap.read()
print success
>>> True
I want to send an Image object in a flask response but it gives me an error. I tried also an approach with StringIO.
image = Image.open("./static/img/test.jpg")
return send_file(image, mimetype='image/jpeg')
This is just a test case. So the major problem is to capture an image from /dev/video0 and sent it (ideally without temporary storing on disk) to the client. I use v4l2capture for that. The test picture should also work if you may have a better solution for that task.
import select
import v4l2capture
video = v4l2capture.Video_device("/dev/video0")
size_x, size_y = video.set_format(1280, 1024)
video.create_buffers(1)
video.queue_all_buffers()
video.start()
select.select((video,), (), ())
image_data = video.read()
video.close()
image = Image.fromstring("RGB", (size_x, size_y), image_data)
Thanks.
EDIT
Works now. Better solutions as v4l2capture are welcome...
Did it with.
image = Image.open("./static/img/test.jpg")
img_io = StringIO()
image.save(img_io, 'JPEG', quality=70)
img_io.seek(0)
return send_file(img_io, mimetype='image/jpeg')
Using mutagen, I am able to add normal metatags such as title, artist, and genre however when I try to add an image via a url, it doesn't work.
from mutagen.mp4 import MP4
from mutagen.mp4 import MP4Cover
from PIL import Image
import urllib2 as urllib
import io, sys, getopt
#url is defined elsewhere
audio = MP4(url)
#clear previous meta tags
audio.delete()
#get album picture data
cover ="http://cont-sv5-2.pandora.com/images/public/amz/5/2/9/7/095115137925_500W_488H.jpg"
fd = urllib.urlopen(cover)
image_file = io.BytesIO(fd.read())
ima = Image.open(image_file)
im = ima.tostring()
#processing
#I think it is here where it breaks
covr = []
if cover.endswith('png'):
covr.append(MP4Cover(im,MP4Cover.FORMAT_PNG))
else:
covr.append(MP4Cover(im,MP4Cover.FORMAT_JPEG))
#add cover
audio['covr'] = covr
#save everything
audio.save()
I know it adds all tags except the image because I can open it with
itunes correctly, all except the album art is blank
when I do ima.show() it gives me the image
because of this I believe that it probably breaks around this line:
covr.append(MP4Cover(im,MP4Cover.FORMAT_JPEG))
any ideas? Is there another way to get the image from a url?
This works for me:
fd = urllib.urlopen(cover)
# Drop the entire PIL part
covr = MP4Cover(fd.read(), getattr(
MP4Cover,
'FORMAT_PNG' if cover.endswith('png') else 'FORMAT_JPEG'
))
fd.close() # always a good thing to do
audio['covr'] = [covr] # make sure it's a list
audio.save()