savonet / liquidsoap

Liquidsoap is a statically typed scripting general-purpose language with dedicated operators and backend for all thing media, streaming, file generation, automation, HTTP backend and more.
http://liquidsoap.info
GNU General Public License v2.0
1.41k stars 130 forks source link

liquidsoap 2.3.0* unable to grab mpegts and avoid transcoding #3425

Closed xogium closed 1 year ago

xogium commented 1 year ago

I'm trying to use the following script in order to grab the audio and video from obs and pass it to liquidsoap. Since obs is already encoding, I'm attempting to use the audio and video copy of ffmpeg in order to avoid encoding again.

The problem comes from the input itself. Liquidsoap seems unable to find a decoder to handle the stream. It is a standard stream from obs, mpegts format, content_type=video/m2ts. The audio is mp2 and the video codec is mpeg2video. Nothing that ffmpeg should have trouble decoding, I imagine.

live = input.harbor("harbor",port=8006,user="username",password="password",icy=true,buffer=6.0,max=12.0)

output.icecast(%ffmpeg(format="mpegts",
        %audio.copy,
        %video.copy),
    send_icy_metadata = true,
    transport = http.transport.tls(),
    host = "radio.domain.tld",
    port = 8443,
    mount = "/vstream.ts",
    password = "password",
    live)

The error I get is 2023/09/23 16:41:37 [decoder:3] Unable to find a decoder for stream mime-type "video/m2ts" with expected content {audio=ffmpeg.copy,video=ffmpeg.copy}!

What am I missing/doing wrong?

vitoyucepi commented 1 year ago

Hi @xogium,

I need to ask a few questions so I can try to reproduce your problem

  1. What OS are you running liquidsoap on?
  2. What version of liquidsoap are you running?
  3. How did you install liquidsoap?

It is a standard stream from obs, mpegts format, content_type=video/m2ts. The audio is mp2 and the video codec is mpeg2video.

Obs recording settings in advanced mode

Looks not very standard. Is it necessary to stream in mpeg2 to icecast?

Why wouldn't you use input.rtmp or input.srt?

xogium commented 1 year ago

Hi! I run liquidsoap installed via opam on archlinux. I currently run the very latest code in the main branch.

As for why I did icecast, well. I initially streamed directly to icecast using this technic. I noticed a few problems with it, such as the fact that you can't use multiple words when defining stream name and genre, no matter if you quote them or not. Another advantages of using ls is that I can mix in audio of the stream with a playlist in the background eventually -- obs is on windows, ls is on linux.

As for why no rtmp/srt, I simply have no clue how these works, nor how to configure them in obs.

Hope this helps!

xogium commented 1 year ago

One thing I forgot to mention is that I am unsure what format to use other than this. I've tried webm but it keeps crashing obs unfortunately, so I stick with the format that wors, which just so happened to be mpegts.

vitoyucepi commented 1 year ago

As for why no rtmp/srt, I simply have no clue how these works, nor how to configure them in obs.

To stream from OBS you should configure custom server in the stream settings. OBS rtmp settings And use the streaming tab in the output settings. OBS stream settings

The liquidsoap live could be configured like this

live = input.rtmp('rtmp://0.0.0.0:8000/a/b')

installed via opam on archlinux

Also available in aur.

xogium commented 1 year ago

Hi, unfortunately the screenshots you've sent are not useful to me since I'm blind. Can you explain in text please?

As for the aur package, I've tried to use that, but I've had too many issues with it and stick to opam these days. I kept having problems to compile this or that, and it was just too much mess to maintain. Opam is much easier. But thanks for pointing it out!

vitoyucepi commented 1 year ago

Can you explain in text please?

Sure.

  1. Open settings: File -> Settings.
  2. In the left column navigate to Stream.
  3. In the right pane from the Service dropdown list select Custom.
  4. In the Server text input field write rtmp://YOUR_SERVER_ADDRESS:PORT/ENDPOINT. Replace YOUR_SERVER_ADDRESS with the correct address of your server. Replace PORT with the port of the server, for example 8000. Replace ENDPOINT with the path to the application, for example, app.
  5. In the Stream key input field write YOUR_SECRET_KEY, for example, b.
  6. In the left column navigate to Streaming.
  7. In the right pane from the Output Mode dropdown list select Simple.
  8. In the Video Bitrate input field write the video bitrate, for example, 2500 Kbps.
  9. From the Audio Bitrate dropdown list select the audio bitrate, for example 160.
  10. From the Video Encoder dropdown list select the video encoder, for example, Software (x264).
  11. From the Encoder Preset dropdown list select the encoder speed/quality, for example, veryfast.
  12. Don't enable Custom Encoder Settings.
  13. From the Audio Encoder dropdown list select the audio encoder, for example AAC.
  14. That's all, you can now save settings.

To configure the liquidsoap you can use input.rtmp. This function accepts string in format "rtmp://IP_ADDRESS:PORT/ENDPOINT/YOUR_SECRET_KEY"

You can store encoder settings in the variable. enc = %ffmpeg(%audio.copy, %video.copy, format="mpegts")

Here's the resulting liquidsoap script

live = input.rtmp("rtmp://0.0.0.0:8000/app/b")

enc = %ffmpeg(%audio.copy, %video.copy, format="mpegts")

output.icecast(
  enc,
  live,
  transport = http.transport.tls(),
  host = "radio.domain.tld",
  port = 8443,
  mount = "/vstream.ts",
  password = "password",
)

But there's a catch ffmpeg has not implemented strict verification for endpoint and key. The patch was discussed but hasn't been merged.

The other possibility is to use SRT. OBS has a guide about SRT streaming. The header of the section is Stream with SRT. To stream using SRT you should change the settings.

  1. Open settings: File -> Settings.
  2. In the left column navigate to Stream.
  3. In the right pane from the Service dropdown list select Custom.
  4. In the Server text input field write srt://YOUR_SERVER_ADDRESS:PORT?passphrase=YOUR_PASSPHRASE. Replace YOUR_PASSPHRASE with a random passphrase with a length from 10 to 79 symbols.

In the liquidsoap config use the input.srt function instead of input.rtmp. The input.srt function has a lot of options. The most useful are

The liquidsoap with the SRT will look like

live = input.srt(
  bind_address="0.0.0.0",
  port=8000,
  passphrase="YOUR_PASSPHASE",
  enforced_encryption=true,
)

enc = %ffmpeg(%audio.copy, %video.copy, format="mpegts")

output.icecast(
  enc,
  live,
  transport = http.transport.tls(),
  host = "radio.domain.tld",
  port = 8443,
  mount = "/vstream.ts",
  password = "password",
)
xogium commented 1 year ago

Thank you so much! This works as I need now.

Fwiw, I chose srt, seemed the less annoying of them to set up.

I'm still curious why the mpegts stream didn't want to get through ffmpeg, that said. Any ideas on that one?

vitoyucepi commented 1 year ago

I'm still curious why the mpegts stream didn't want to get through ffmpeg, that said. Any ideas on that one?

You can enable option Show all codecs, like it's done in the ePirat's blog post. This option will enable you to choose libx264 as the video encoder and aac as the audio encoder. But there was an error. The configured value for Muxer Settings is content_type=video/mp2ts. This is the incorrect mime type for mpegts. It should be video/mp2t, not video/mp2ts. It's also possible to leave this field empty.

  1. In the left column navigate to Output.
  2. In the right pane from the Output Mode dropdown list select Advanced.
  3. Navigate to Recording.
  4. From the Type dropdown list select Custom Output (FFmpeg).
  5. From the FFmpeg Output Type dropdown list select Output to URL.
  6. In the File path or URL text input field write the Icecast URL, for example, icecast://source:hackme@127.0.0.1:8000/example.ts.
  7. From the Container Format dropdown list select mpegts.
  8. In the Muxer Settings text input field write muxer settings. You can leave this field empty.
  9. In the Video Bitrate number input field write the desired video bitrate, for example, 2500 Kbps.
  10. In the Keyframe interval number input field write the interval between the key frames. The recommended number for streaming is 2 seconds multiplied by FPS. For 30 frames per second, this value should be 60.
  11. Enable option Show all codecs.
  12. From the Video Encoder dropdown list select a video codec, for example, libx264.
  13. In the Video Encoder Settings text input field write the settings like preset.
  14. In the Audio Bitrate number input field write the desired audio bitrate, for example, 160 Kbps.
  15. From the Audio Encoder dropdown list select an audio codec, for example aac.

By the way, I have found another type of error. It's not possible to set another encoder without restarting the liquidsoap when copy-codec is used.

toots commented 1 year ago

Hi all! This great and helpful. For future reference, decoder mime types for ffmpeg (and others) can be set at runtime using settings.decoder.mime_types.ffmpeg: doc here

input.harbor wouldn't seem like the most suited input for OBS indeed. The two typical method with it are rtmp or srt.

Thanks for all the details. I'm converting this to a discussion so it can stick around.