SamuelScheit / puppeteer-stream

A Library for puppeteer to retrieve audio and/or video streams
MIT License
335 stars 105 forks source link

[Question] How can I stream directly via express.js? #62

Closed BrandonQDixon closed 1 year ago

BrandonQDixon commented 1 year ago

I have an express js server and I want to create an endpoint to stream the output "Stream" object as a live video. I've got everything setup where I create the browser instance, page object, send the html, and get the stream object, but from there, I'm not sure how to create the endpoint to actually allow a consumer to stream it as a video. I know this isn't directly related to this library but any help would be appreciated!

SamuelScheit commented 1 year ago

Write this in your route handler:

stream.pipe(response)

BrandonQDixon commented 1 year ago

Ah, thanks! I was focusing on making the reverse work the whole time, response.pipe(stream). I can see that the stream is emitting continuously, but if you don't mind, I'd like to ask how I can encode it in such a way that a video element can play it?

SamuelScheit commented 1 year ago

you have to set the content-type response header:

res.setHeader('content-type', 'video/webm');
BrandonQDixon commented 1 year ago

It looks like from the client, I won't be able to plug the endpoint src right into a video HTML element. After trying this, the video element perpetually shows a loading icon. Will I need to open an http request, parse into some type of buffer or series of blobs, and feed each blob into the video one by one?

SamuelScheit commented 1 year ago

Maybe this will help: https://stackoverflow.com/questions/66644023/html5-is-it-possible-to-live-stream-a-webm-as-its-being-generated https://github.com/yomguy/stream-m

BrandonQDixon commented 1 year ago

Thanks for the references! After reading those, plus debugging a bit, I believe my server is still not delivering the stream correctly. I've also tried to open the stream on VLC media player and am experiencing basically the same issue, it is always loading and the video is never being rendered. I believe my issue is that the "GET" endpoint is continuously sending data and never stops. but the client is expecting the response to stop being written after a certain point, so I believe I'll need to write logic to implement buffering in that way.

antoniott15 commented 1 year ago

same issue here, when i log the pipe data seems that data has created but is never sended to the client stream.pipe(res, { end: false }) stream.on('data', (data) => { console.log(data) })

this are the headers that I've ended to client const headers = { 'Transfer-Encoding': 'chunked', 'Content-Type': 'video/webm', 'Accept-Ranges': 'bytes' }

BrandonQDixon commented 1 year ago

In my case, I can see that I'm getting data to the client by opening the stream url directly, I think I'm just not quite sending it back correctly. Are you using a 'GET' method for this?

antoniott15 commented 1 year ago

yes!

BrandonQDixon commented 1 year ago

Actually, thank you for sharing those headers! With those, I was able to get mine working. The stream has about a 30 second delay, both for the video rendering on my HTML and for changes in the source to be reflected on the webpage. I'm fine with that level of delay. I'm not sure why it isn't working in your case though, is the stream happening correctly before that? I don't know if it makes a difference, but my endpoint does include ".webm"

antoniott15 commented 1 year ago

this is my code


app.get('/', async function (req, res) {
    const headers = {
        'Transfer-Encoding': 'chunked', 
        'Content-Type': 'video/webm',
        'Accept-Ranges': 'bytes'
    }

    try {

        const browser = await launch({
            defaultViewport: {
                width: 1920,
                height: 1080,
            },
        })
        const page = await browser.newPage();

        await page.goto("somelink");

        const streamService = await getStream(page, { audio: false, video: true, mimeType: "video/webm" });

        res.writeHead(206, headers);
        streamService.pipe(res, { end: false })

    }catch(e) {
        console.log(e)
    }

})

idk if I'm doing something wrong here

the client

       <video id="videoPlayer" width="50%" controls muted="muted" autoplay>
            <source src="http://localhost:3000/" type="video/webm" />
        </video>
BrandonQDixon commented 1 year ago

I don't know if it makes a difference, but maybe change "/" to "/video.webm". What is the purpose of the 206 header? I'm not using that in mine.

antoniott15 commented 1 year ago

as far as i know needs to be used when sends ranges of data

jonmumm commented 1 year ago

@BrandonQDixon I'm trying to do this same thing—bychance do you have a working sample code you could post? I'm seeing the same issue where the webm player in chrome just keeps spinning. I see a few bytes come in over the stream when setting up the data listener, but then it stops sending bytes

SamuelScheit commented 1 year ago

Have a look at the example server file.