29

I'm trying to run end-to-end testing in Chrome for a product that requires a webcam feed halfway through to operate. From what I understand this means providing a fake webcam video to Chrome using the --use-file-for-fake-video-capture="/path/to/video.y4m" command line argument. It will then use that as a webcam video.

However, no matter what y4m file I provide, I get the following error from Chrome running under these conditions:

DOMException: Could not start video source
{
  code: 0,
  message: "Could not start video source",
  name: "NotReadableError"
}

Notably I can provide an audio file just fine using --use-file-for-fake-audio-capture and Chrome will work with it well. The video has been my sticking point.

This error comes out of the following straightforward mediaDevices request:

navigator.mediaDevices.getUserMedia({ video: true, audio: true })
  .then(data => {
    // do stuff
  })
  .catch(err => {
    // oh no!
  });

(This always hits the “oh no!” branch when a video file is provided.)

What I've tried so far

I've been running Chrome with the following command line arguments (newlines added for readability), and I'm using a Mac hence the open command:

open -a "Google Chrome" --args
  --disable-gpu
  --use-fake-device-for-media-stream
  --use-file-for-fake-video-capture="~/Documents/mock/webcam.y4m"
  --use-file-for-fake-audio-capture="~/Documents/mock/microphone.wav"

webcam.y4m and microphone.wav were generated from a video file I recorded.

I first recorded a twenty-second mp4 video using my browser's MediaRecorder, downloaded the result, and converted it using the following command line commands:

ffmpeg -y -i original.mp4 -f wav -vn microphone.wav
ffmpeg -y -i original.mp4 webcam.y4m

When this didn't work, I tried the same using a twenty-second movie file I recorded in Quicktime:

ffmpeg -y -i original.mov -f wav -vn microphone.wav
ffmpeg -y -i original.mov webcam.y4m

When that also failed, I went straight to the Chromium file that explains fake video capture, went to the example y4m file list it provided, and downloaded the grandma file and provided that as a command line argument to Chrome instead:

open -a "Google Chrome" --args
  --disable-gpu
  --use-fake-device-for-media-stream
  --use-file-for-fake-video-capture="~/Documents/mock/grandma_qcif.y4m"
  --use-file-for-fake-audio-capture="~/Documents/mock/microphone.wav"

Chrome provides me with the exact same error in all of these situations.

The only time Chrome doesn't error out with that mediaDevices request is when I omit the video completely:

open -a "Google Chrome" --args
  --disable-gpu
  --use-fake-device-for-media-stream
  --use-file-for-fake-audio-capture="~/Documents/mock/microphone.wav"

Accounting for C420mpeg2

TestRTC suggests Chrome will “crash” if I give it a C420mpeg2 file, and recommends that simply replacing the metadata fixes the issue. Indeed the video file I generate from ffmpeg gives me the following header:

YUV4MPEG2 W1280 H720 F30:1 Ip A1:1 C420mpeg2 XYSCSS=420MPEG2

Chrome doesn't actually crash when run with this file, I just get the error above. If I edit the video file to the following header though per TestRTC's recommendations I get the same situation:

YUV4MPEG2 W1280 H720 F30:1 Ip A1:1 C420 XYSCSS=420MPEG2

The video file still gives me the above error in these conditions.

What can/should I do?

How should I be providing a video file to Chrome for this command line argument?

How should I be recording or creating the video file?

How should I convert it to y4m?

doppelgreener
  • 4,809
  • 10
  • 46
  • 63

4 Answers4

43

After reading the link you provided I noticed that we can also provide an mjpeg.

Depending on what your test requirements - this may be sufficient for you. As a terminal command with ffmpeg installed:

ffmpeg -i oldfile.mp4 newfile.mjpeg

then I tested by running Google Chrome from the terminal using:

google-chrome --use-fake-device-for-media-stream --use-file-for-fake-video-capture=newfile.mjpeg

After navigating to Tracking JS I could see the video being played back.

I hope that works for you!

doppelgreener
  • 4,809
  • 10
  • 46
  • 63
Matt Harvey
  • 854
  • 8
  • 5
  • Precise solution for simulating a webcam for chrome without a loopback device. great work. – S.K. Venkat Nov 14 '19 at 06:59
  • 3
    Hi, where do I write these lines ? – Benoît Aug 13 '20 at 16:03
  • 1
    Also, if someone wants to generate a video from a single repeated image, you can do it as: `ffmpeg -loop 1 -i inputImage.png -pix_fmt yuv420p -t 0.05 outputVideo.y4m` (Chrome loops the video, so you don't need to worry about the duration.. I specified 0.05 seconds so that the created file is small) – LGenzelis Feb 04 '22 at 23:39
7

If someone ever needs to mock a video dynamically, this is what I've used (forked from here)

await page.evaluate(() => {
        const video = document.createElement("video");

        video.setAttribute('id', 'video-mock');
        video.setAttribute("src", 'https://woolyss.com/f/spring-vp9-vorbis.webm');
        video.setAttribute("crossorigin", "anonymous");
        video.setAttribute("controls", "");

        video.oncanplay = () => {
            const stream = video.captureStream();

            navigator.mediaDevices.getUserMedia = () => Promise.resolve(stream);
        };

        document.querySelector("body").appendChild(video);
    });

This flags are still necessary:

'--use-fake-ui-for-media-stream',
'--use-fake-device-for-media-stream',

In the end, with this script different camera mocks are possible for every page - especially useful when using browserless!

7

Mocked/Fake Raw Video (2021)

Use y4m if you want raw frames without Chrome having to run a decoder:

ffmpeg -i original.avi -pix_fmt yuv420p video-for-chrome.y4m

Then, start Chrome:

chrome.exe --use-fake-device-for-media-stream --use-file-for-fake-video-capture=video-for-chrome.y4m

Note: There is no longer any reason to have to modify your y4m file's header. Chrome has since been fixed.

This method uses less CPU, but will take up a good deal of hard drive space for the raw video. Keep your video file short. Chrome will loop it.

Brad
  • 159,648
  • 54
  • 349
  • 530
  • 1
    this solution worked for me, I'm using playwright for opening the browser – civanm Sep 16 '21 at 20:48
  • 1
    this doesn't seem to work on windows, but works on mac. Can anyone confirm? – No_name Oct 06 '21 at 21:15
  • @No_name I'm using this on Windows. – Brad Oct 07 '21 at 01:09
  • 1
    on linux I had to specify the size in order for this to work I've used: `ffmpeg -i original.png -pix_fmt yuv420p -s 1280x720 video-for-chrome.y4m` and worked – civanm Nov 11 '21 at 18:10
  • 1
    @brad, thanks for your answer! Please note that it should be `--use-fa...` instead of `--user-fa...`. See [this link](https://webrtc.github.io/webrtc-org/testing/) for other options – LGenzelis Feb 04 '22 at 21:17
  • @No_name I can confirm this is NOT working on `Windows 10 Home Build 19043.1526` and `Chrome Version 98.0.4758.102 (Official Build) (64-bit)`. I am calling it like this `& "C:\Program Files\Google\Chrome\Application\chrome.exe" '--use-fake-device-for-media-stream --use-file-for-fake-video-capture=test.y4m'`, but it's still using the real webcam everywhere (e.g.: https://webcamtests.com/). – Fappaz Feb 17 '22 at 23:11
  • @Fapaz Drop those quotes around your args. – Brad Feb 17 '22 at 23:28
  • @Brad Apologies, that was copied from one of my many tests. This still doesn't work: `& "C:\Program Files\Google\Chrome\Application\chrome.exe" --use-fake-device-for-media-stream --use-file-for-fake-video-capture=test.y4m`. I also tried ditching the fake video capture, added the arguments in the Target of a shortcut, executed ffmpeg with different parameters, etc. Can't find much online either, so I'm wondering whether this Chrome flag has been compromised recently. – Fappaz Feb 18 '22 at 00:10
  • Progress! I went to chrome://version on my browser and noticed that none of the flags were present in `Command Line`. So I closed all Chrome instances (as instructed [here](https://www.chromium.org/developers/how-tos/run-chromium-with-flags/#windows)) and executed the shell command again. It works now... partially. If I provide just the `--use-fake-device-for-media-stream`, it fakes the stream with a default test video as expected. However, the webcam is not being detected anywhere if I provide a fake video capture (either y4m or mjpeg). – Fappaz Feb 18 '22 at 00:47
  • @Fapaz Yes, your webcam will no longer work if you're using a faked media stream. – Brad Feb 18 '22 at 01:05
  • @Brad Sorry I mean the fake video stream wasn't working at all. Eventually I figured out that I had to provide the absolute path to the fake video instead. As I couldn't edit your answer, I posted my own down below. I have upvoted yours anyway, thanks. – Fappaz Feb 18 '22 at 01:47
5

How to mock webcam on Chrome for Windows

(Tested with Windows 10 Home Build 19043.1526 and Chrome Version 98.0.4758.102 (Official Build) (64-bit))

Install ffmpeg, then run the following command in your shell to convert your mp4 to mpjeg:

./ffmpeg.exe -i originalVideo.mp4 output.mjpeg

Alternatively, you could also create a y4m video from a png image (thanks @LGenzelis):

./ffmpeg.exe -loop 1 -i myStaticImage.png -pix_fmt yuv420p -t 0.05 output.y4m

Close all Chrome instances, then run the following command in your shell:

"C:\Program Files\Google\Chrome\Application\chrome.exe" --use-fake-device-for-media-stream --use-file-for-fake-video-capture="C:/absolute/path/to/output.mjpeg"

Then test it on a website like https://webcamtests.com/

Troubleshooting

Chrome still showing stream from real camera

Make sure there are no other Chrome instances running before launching it with those arguments.

Camera not found

Make sure you're providing the absolute path to your video in --use-file-for-fake-video-capture (e.g.: "C:/absolute/path/to/output.mjpeg" instead of just output.mjpeg)

Fappaz
  • 3,033
  • 3
  • 28
  • 39
  • Using the absolute path fixed it for me. But I had to remove the `&` from the beginning of the command to launch Chrome - not sure what that was intended for. – Tim MB Dec 14 '22 at 23:19
  • @TimMB that's probably a typo or leftover while copying/pasting, it's been fixed, thanks. – Fappaz Dec 15 '22 at 01:16