Byte range requests from aws S3 - amazon-web-services

guys so I have a problem consistently and reliably seeking videos with HTML5. I am getting the videos from an AWS S3 Bucket using Nodejs all videos are in mp4 format. I have tried multiple things to get the video's current time to move every time (most of the time it works but occasionally it doesn't move) but to no avail.
Heres my code:
router.get("/*", (req, res, next) => {
let params = {
Bucket: "bucketName",
Key: decodeURIComponent(req.path.substring(1))
};
s3.getObject(params, function(err, data) {
if (err) {
res.status(500).send(err);
} else {
res.contentType(data.ContentType);
res.send(data.Body);
}
});
});
}
I've been doing some reading and people are saying you can use byte-range requests and request the whole video through a byte-range request. This guy seems to do it with a local file but I am at a loss about how to do it with an s3 file. See post: can't seek html5 video or audio in chrome. The other suggestion I've heard of people doing is HLS encoding but I am not sure what is the best way or how to implement them can someone point me in the right direction?

I think the best answer is probably to implement an HLS or DASH streaming solution. Here is an example of HLS with S3 and CloudFront. And here is a more comprehensive Best Practices for Streaming Media Delivery.
Right now, your app server is simply reading the entire video file from S3 and then sending the entire video file contents directly to the client in an HTTP response. While it appears to work, it might be better to avoid proxying this content, and instead serve it directly to the client from S3 (or CloudFront). One way to do that, for private content, is to send the client an S3 pre-signed URL.
I tested a simple HTML5 video web page against an S3-hosted MPEG video file and was able to view it fine on Chrome, as well as seek back and forth at will. I tested with a relatively small MPEG (15MB).
<html>
<body>
<h1>Stack Overflow 65796272 Video Sample</h1>
<p>This video and associated poster are sourced from Amazon S3 via pre-signed URL.</p>
<div id="container">
<video id='video' controls="controls" preload='none' width="600" poster="https://poster-presigned-url-here">
<source id='mp4' src="https://video-presigned-url-here" type='video/mp4' />
<p>Your user agent does not support the HTML5 video element.</p>
</video>
</div>
</body>
</html>
I pre-created the poster and video pre-signed URLs using the awscli, but you can do this using an AWS SDK and serve them dynamically to your client (or inject them into the HTML sent to the client using any standard template engine such as Express.js). You can remove the poster, if not needed. Note that pre-signed URLs are time-limited.

Related

How can I Upload a feed via postman to Amazon Sp-API?

I've spent weeks, hours daily trying to figure out how to upload a feed (POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA) to Amazon sp API.
Before even attempting to do it in PHP, I want to 1st make it work on Postman.
I've been successful getting a FEED ID and a FEED URL (I Used content type: "text/xml; charset=UTF-8" since it's a flat file (CSV not XML).
Although, If I can make it work easier via XML I Would gladly switch. I just want to be able to update my inventory and price in same feed.
Are there are links to a postman configuration to upload to a feed?
I think I'm supposed to use "PUT" and upload to the Feed url but I can't find an already complete postman config for it.
Any help would be soooooooo appreciated.
Thank you so much!

AWS S3 - automatically change response header

Our team is building a web app that allows users to download video files. We currently host our files on AWS S3, but since our site doesn't reside on AWS, we can't use <a href="blah"> to prompt download. If we use that html element, users simply get redirected to a video player - which is fine, but Safari on mobile doesn't allow for users to download the video file via the video player.
We found that manually setting the file's content disposition to attachment on S3 works, but we have not found a way to automate that. We tried adding a content-disposition: attachment key-value pairing in our payload, which works, but adds a "User defined" meta data in the form of x-amz-meta-content-disposition, which doesn't work as the file could not be downloaded as an attachment. It seems only "System defined" works.
Has anyone ever encountered this issue before and found a workaround?
see screenshot for what I'm referencing
You can set the content disposition when the file is created.
This is done by uploading the file via a presigned url.
See https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html for details on the presigned urls.
Alternatively you can use a presigned url to return to get the file from S3 and override the content disposition header on the GET request.

How to stream a presigned video from an AWS S3 bucket?

When generating a presigned video URL from AWS S3 bucket the video will download in mp4 format if I use the URL in the web browser , however, it will not stream if I put it in the src attribute of a video tag. Below is an example of what the presigned url looks like. How can I use this url to stream?
<video width="320" height="240" controls preload="auto">
<source src="https://s3.eu-north-1.amazonaws.com/daycare.videos/iland-guard/yamit/2020-12-09/cam_0/20201209_043123.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA6OHOPCC5DWJXXO7O%2F20210309%2Feu-north-1%2Fs3%2Faws4_request&X-Amz-Date=20210309T075948Z&X-Amz-Expires=900&X-Amz-Signature=1cfb2dc7658b90714cd5b52b157f3caf878be6504a4d5f9d1a1be76a599abae8&X-Amz-SignedHeaders=host" type="video/mp4">
</video>
To test this, I did the following:
Put an .mp4 file in an Amazon S3 bucket (no Bucket Policy, no ACL)
Generated a pre-signed url using the AWS CLI aws s3 presign command
Tested the pre-signed URL by pasting it into a browser Address Bar -- it worked
Substituted the pre-signed URL in your code (above) -- it worked
I did have a strange problem with a space in the filename -- I had to quote the path for the AWS CLI to include the raw space rather than using a + to represent the space.
The pre-signed URL that was generated looked like this:
https://bucketname.s3.amazonaws.com/A2%20File.mp4?AWSAccessKeyId=AKIAxxx&Signature=xxx&Expires=1615413373
I see that it uses a different format to the one presented in your question.
I replicated above, using the Node library. The code seems to work fine. The key thing to make sure is whether the presigned URL works when placed in your browser. The SDK generates a URL regardless of whether the file exists or not, so make sure the presigned URL is actually functioning.
The format of my presigned URL matches that of yours:
<video width="320" height="240" controls preload="auto">
<source src="https://bucket.s3.ca-central-1.amazonaws.com/Glass%20one/2e71b368-1d22-4c56-a690-b534eea3def8.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAQOTARPS7GGSVO5F7%2F20210915%2Fca-central-1%2Fs3%2Faws4_request&X-Amz-Date=20210915T223104Z&X-Amz-Expires=3600&X-Amz-Signature=f61fc82b7ebd55ea83290587786d61fe41cb6137624d243bf36c46257ef2aab6&X-Amz-SignedHeaders=host&x-id=GetObject" type="video/mp4">
</video>

Playing an mp3 created by AWS api gateway in an Alexa skill

I have an AWS lambda function that is called by AWS api gateway. The function takes URLs from multiple mp3 files hosted on AWS S3 and concatenates them into a single mp3 file. When I call the api from a browser all is good (the browser opens a media player and the combined audio mp3 is played).
The URL request looks like this:
https://0xxxxxxxx.execute-api.eu-west-1.amazonaws.com/alpha/files?file=https://xxx.s3-eu-west-1.amazonaws.com/file1.mp3&file=https://xxx.s3-eu-west-1.amazonaws.com/file2.mp3&file=https://xxx.s3-eu-west-1.amazonaws.com/file3.mp3
the HTTP response is of type audio/mpeg, about 10 seconds long, and is base64 encoded.
I've tried to wrap this into SSML in my skill and it fails. From the Alexa skills kit voice and tone simulator, I get the error message "error retrieving text to speech; the input was incompatible"
In the simulator, this is what I wrote:
<speak>
<audio src='https://0xxxxxxxx.execute-api.eu-west-1.amazonaws.com/alpha/files?file=https://xxx.s3-eu-west-1.amazonaws.com/file1.mp3&file=https://xxx.s3-eu-west-1.amazonaws.com/file2.mp3&file=https://xxx.s3-eu-west-1.amazonaws.com/file3.mp3'/>
</speak>
and I used this to confirm that S3 access works in the simulator:
<speak>
<audio src='https://s3.amazonaws.com/ask-soundlibrary/human/amzn_sfx_crowd_applause_05.mp3'/>
</speak>
Any ideas what is wrong? Is the issue with the http response from my lambda skill, or does something need to be enabled in api gateway? From my api gateway logs, it seems that the skill never tries to access the gateway.
Should I be using a different approach to fetch the mp3 for playback? Note, i want to use SSML as my audio is an effect and therefore shouldn't use the audioplayer (This is an Amazon requirement).
I might help you with this. The same problem happened to me. And after researching I resolved it. The problem here is "&" in you link which you provide in SSML. The solution you provided worked because there is no "&" now in your link. Too many parameters is not the problem.
I will suggest you to replace "&" with "&"
In python -
url = 'https://0xxxxxxxx.execute-api.eu-west-1.amazonaws.com/alpha/files?file=https://xxx.s3-eu-west-1.amazonaws.com/file1.mp3&file=https://xxx.s3-eu-west-1.amazonaws.com/file2.mp3&file=https://xxx.s3-eu-west-1.amazonaws.com/file3.mp3'
url = url.replace("&","&")
<speak>
"<audio src='" + url + "'/>"
</speak>
I hope this helps you. Please let me know if doesn't work.
Ok, I've worked it out myself.
It seems that SSML audio src doesn't like too many parameters in the URL call. I now just pass 1 parameter in the URL and use my lambda function to strip out the multiple filenames frome that single parameter.
https://0xxxxxxxx.execute-api.eu-west-1.amazonaws.com/alpha/files?file=/file1.mp3file=file2.mp3file=file3.mp3

How to sign an RTMP url for Amazon CloudFront

I'm trying to create signed urls for an RTMP distribution in Amazon's CloudFront. I have the following working:
Signed URLs for Web distribution (over http and https) - so I know I am able to sign URLs correctly.
Unsigned URLs for RTMP distribution - so I know I have CloudFront and S3 setup properly for RTMP.
Main question - now that I'm trying to get a signed url for RTMP, it never seems to be playable.
Part of the confusion is based on the format of the url (similar to this question). So I don't know if it matters which part of the url I sign - if I sign the whole thing (like my http urls), or if I only sign a portion, and if I include the mp4: prefix in the path.
There seem to be a lot of pseudo-similar questions on Stackoverflow, but they seem to be related to slightly different issues, and not about actually creating a signed url for RTMP.
Unfortunately there are many variations to how a RTMP url can be created, which
caused a large portion of the confusion. The following is the way that I was able to get this to work with Amazon CloudFront. To be clear, this was to be used in a *.SMIL file, so it might be different if you only need a single url.
The S3ObjectSummary object has a key for the file, which might be something like folder1/folder2/video.mp4.
Use the above key, and remove the .mp4 extension.
Sign the url as normal (I used CloudFrontService.signUrlCanned().
In the *.smil file that is generated, set the base reference to rtmp://<CloudFront RTMP Distribution Domain>/cfx/st
In the video element, set the height and width, and in the src attribute, prepend mp4: to the signed url portion.
Here is an example SMIL file.
<smil data-livestyle-extension="available">
<head>
<meta base="rtmp://some-cloud-front-domain.net/cfx/st"/>
</head>
<body>
<switch>
<video height="720" width="1280" src="mp4:<signed portion of video path>" />
<video height="480" width="853" src="mp4:<signed portion of video path>" />
</switch>
</body>
</smil>
With Python/boto3, I've managed to sign media files with the rsa_signer
http://boto3.readthedocs.io/en/latest/reference/services/cloudfront.html#generate-a-signed-url-for-amazon-cloudfront
by signing only the path to the media file.
Let's say you want to stream an S3 bucket media file located at 'videos/test.mp4'
Following the boto3 example from the link above, here's what you can do to serve the file with flowplayer:
signed_url = cloudfront_signer.generate_presigned_url(
'videos/test.mp4', date_less_than=expire_date)
Then in the flowplayer code (Django template syntax):
<div class="flowplayer fp-slim" data-rtmp="rtmp://{{cloudfront_domain_prefix}}.cloudfront.net:1935/cfx/st">
<video>
<source type="video/flash" src="mp4:{{signed_src}}">
</video>
</div>