Invalid buffer timestamps when trans-muxing HLS stream to MKV

Hi all! I am working on a small project to trans-mux YouTube videos into a single file for playback in a social VR game.

I’m running into issues when using urisourcebin to download and de-mux the HLS playlist from YouTube.

This is my pipeline:

gst-launch-1.0 --gst-debug 3 `
    matroskamux name=mux ! filesink location="video.mkv" `
    urisourcebin uri="$(yt-dlp --get-url https://www.youtube.com/watch?v=q2RQyrp6j_A -f "bestaudio[ext=m4a]")" ! qtdemux ! audio/mpeg ! queue2 ! mux.audio_0 `
    urisourcebin uri="$(yt-dlp --get-url https://www.youtube.com/watch?v=q2RQyrp6j_A -f "bestvideo[ext=mp4]")" ! video/x-vp9 ! vp9parse ! queue2 ! mux.video_0

These are the errors I’m seeing along with a corrupted video:

Setting pipeline to PLAYING ...
Buffering, setting pipeline to PAUSED ...
0:00:01.055796800 87356 00000178EA891F40 FIXME                qtdemux qtdemux_types.c:269:qtdemux_type_get: unknown QuickTime node type vp09
Done buffering, setting pipeline to PLAYING ...
0:00:01.057932600 87356 00000178EA4D8280 FIXME               basesink gstbasesink.c:3401:gst_base_sink_default_event:<filesink0> stream-start event without group-id. Consider implementing group-id handling in the upstream elements
Buffering, setting pipeline to PAUSED ...
0:00:01.060693200 87356 00000178EA4D8240 WARN             matroskamux matroska-mux.c:4058:gst_matroska_mux_write_data:<mux:video_0> Invalid buffer timestamp; dropping buffer
Redistribute latency...
New clock: GstSystemClock
Redistribute latency...
Done buffering, setting pipeline to PLAYING ...
0:00:02.144258200 87356 00000178EA4D8240 WARN             matroskamux matroska-mux.c:4058:gst_matroska_mux_write_data:<mux:video_0> Invalid buffer timestamp; dropping buffer
Buffering, setting pipeline to PAUSED ...
0:00:02.146744400 87356 00000178EA4D8240 WARN             matroskamux matroska-mux.c:4058:gst_matroska_mux_write_data:<mux:video_0> Invalid buffer timestamp; dropping buffer
Redistribute latency...
Done buffering, setting pipeline to PLAYING ...
0:00:03.565762900 87356 00000178EA4D8240 WARN             matroskamux matroska-mux.c:4058:gst_matroska_mux_write_data:<mux:video_0> Invalid buffer timestamp; dropping buffer

Interestingly enough, this pipeline does work, using souphttpsrc directly with the do-timestamp=true option:

gst-launch-1.0 --gst-debug 3 `
    matroskamux name=mux ! filesink location="video.mkv" `
    urisourcebin uri="$(yt-dlp --get-url https://www.youtube.com/watch?v=q2RQyrp6j_A -f "bestaudio[ext=m4a]")" ! qtdemux ! audio/mpeg ! queue2 ! mux.audio_0 `
    souphttpsrc do-timestamp=true location="$(yt-dlp --get-url https://www.youtube.com/watch?v=q2RQyrp6j_A -f "bestvideo[ext=mp4]")" ! application/x-hls ! hlsdemux ! video/quicktime ! qtdemux ! video/x-vp9 ! vp9parse ! mux.video_0

Does anyone have any idea what might be going on here + why my buffer timestamps are invalid when using the newer urisourcebin & hlsdemux2?

I wanted to avoid using hlsdemux as it’s frequently been called old / deprecated and is in plugins-bad, but I cannot use hlsdemux2 manually as it’s auto-created inside of urisourcebin and requires a “streams aware” context.

Is there any way to pull this off without using the C API? I also tried with the Java bindings out of curiosity and wasn’t able to make it work by setting a “source-setup” callback on the urisourcebin to set do-timestamps=true on the souphttpsrc that is auto created…

Not really sure what to do. I would like to keep this a simple project and avoid running the pipeline from C or any bindings as this probably will 2-3x the code-base in size, but even with the bindings I’m having no luck. Is there any other pipeline element that can create buffer timestamps that I can just stick after urisourcebin to fix my issue? :smiley:

Something interesting that’s happening as well is mp4mux just straight up doesn’t work, it immediately exits with no error, despite MP4 from what I can tell being able to support VP9 codec. Also, playbin3 uri=xx works just fine as well :confused:

ffmpeg ended up being a better tool for the job:

ffmpeg -user_agent "not even sure if this is needed?" -i "$(yt-dlp --get-url https://www.youtube.com/watch?v=q2RQyrp6j_A -f "bestvideo[ext=mp4]")" -i "$(yt-dlp --get-url https://www.youtube.com/watch?v=q2RQyrp6j_A -f "bestaudio[ext=m4a]")" -c:v copy -c:a libopus -map 0:v -map 1:a -shortest output.webm

Nothing against gstreamer, it’s fantastic, it just can’t do everything in pipeline syntax