7ERr0r / youtubezero

Watch YouTube livestreams with less latency
8 stars 2 forks source link

non-mpegts videos: Not working for many live videos. #1

Closed ajayalag1974 closed 2 years ago

ajayalag1974 commented 2 years ago

Hi,

Thanks for the great program but i need your help as it is not working for many of the live videos. In those cases audio is working as usual but video is working only for first 1-2 seconds than it got stuck at some frame and that too those working seconds have frames much older (starting frames of the live video not the live ones). Sometimes in those case of live videos where it doesn't work as expected suddenly starts working and than after some time suddenly stops workings so its kind of random or may be some pattern, i am not able to figure out how to fix this thing tried some of the things which i could but i am now wanted to take your help if its possible.

What i observed, i monitored network requests with Fiddler to check whether any http requests are failing due to invalid requests, but that was not the case each and every request, audio as well as video requests were successfully completing and data was fetched. See screenshot: image

In command line logs, i see both audio & video download_format_segment status coming 200 but segment joining of audio is completing but segment joining of video is outputing this - ordered_download: segment timed out. Video gets stuck at some initial frame audio is working fine. Video segment joininig process (frame) gets well behind to audio segment joining because of constant time outs for each frame though i see 200 http status in command line logs + fiddler all requests are completing maybe some bug when joining those fetched segments/frame. My knowledge is limited in this context so forgive me if i sound confusing hope you are able to understand the issue and could help me out. Here are the command line logs:

video_url: u7q46nFvFWM
fetch_player_response: Status: 200 OK
137: Some(5018593) / video/mp4; codecs="avc1.640028"
248: Some(1816000) / video/webm; codecs="vp9"
247: Some(1040000) / video/webm; codecs="vp9"
244: Some(528000) / video/webm; codecs="vp9"
243: Some(292000) / video/webm; codecs="vp9"
242: Some(166000) / video/webm; codecs="vp9"
278: Some(111000) / video/webm; codecs="vp9"
386: None / text/mp4; codecs="unknown"
best audio: 140: Some(144000) / audio/mp4; codecs="mp4a.40.2"
136: Some(2684050) / video/mp4; codecs="avc1.4d401f"
160: Some(212465) / video/mp4; codecs="avc1.42c00b"
134: Some(1008250) / video/mp4; codecs="avc1.4d401e"
140: Some(144000) / audio/mp4; codecs="mp4a.40.2"
135: Some(1350025) / video/mp4; codecs="avc1.4d401f"
387: None / text/mp4; codecs="unknown"
133: Some(456228) / video/mp4; codecs="avc1.4d4015"
best video: 137: Some(5018593) / video/mp4; codecs="avc1.640028"
[VID] Downloading: Saturday live for programmers - u7q46nFvFWM - Some(5018593) bit/s, video/mp4; codecs="avc1.640028"
[AUD] Downloading: Saturday live for programmers - u7q46nFvFWM - Some(144000) bit/s, audio/mp4; codecs="mp4a.40.2"
[VID] joining segment 0
[AUD] joining segment 0
[AUD] download_format_segment 0: Status: 200 OK
[VID] download_format_segment 0: Status: 200 OK
[VID] set seqnum to head: 312
[VID] joining segment 312
[AUD] set seqnum to head: 312
[AUD] joining segment 312
[AUD] download_format_segment 312: Status: 200 OK
[AUD] joining segment 313
[VID] download_format_segment 312: Status: 200 OK
[AUD] download_format_segment 313: Status: 200 OK
[VID] joining segment 313
[AUD] joining segment 314
[VID] download_format_segment 313: Status: 200 OK
[VID] joining segment 314
[VID] download_format_segment 314: Status: 200 OK
[AUD] download_format_segment 314: Status: 200 OK
[AUD] joining segment 315
[VID] joining segment 315
[AUD] download_format_segment 315: Status: 204 No Content
[VID] download_format_segment 315: Status: 204 No Content
[VID] download_format_segment 315: Status: 200 OK
[AUD] download_format_segment 315: Status: 200 OK
[AUD] joining segment 316
[VID] download_format_segment 316: Status: 204 No Content
[AUD] download_format_segment 316: Status: 204 No Content
[AUD] download_format_segment 316: Status: 200 OK
[AUD] joining segment 317
[VID] download_format_segment 316: Status: 200 OK
[VID] download_format_segment 317: Status: 204 No Content
[AUD] download_format_segment 317: Status: 204 No Content
[VID] download_format_segment 317: Status: 200 OK
[AUD] download_format_segment 317: Status: 200 OK
[AUD] joining segment 318
[AUD] download_format_segment 319: Status: 200 OK
[AUD] blocked! text/plain
[AUD] download_format_segment 318: Status: 204 No Content
[VID] download_format_segment 318: Status: 204 No Content
[VID] download_format_segment 318: Status: 200 OK

ordered_download: segment timed out
[VID] joining segment 316
[AUD] download_format_segment 318: Status: 200 OK
[AUD] joining segment 319
[AUD] joining segment 320
[VID] download_format_segment 319: Status: 204 No Content
[AUD] download_format_segment 320: Status: 204 No Content
[VID] download_format_segment 319: Status: 200 OK
[VID] download_format_segment 320: Status: 204 No Content
[AUD] download_format_segment 321: Status: 204 No Content
[AUD] download_format_segment 320: Status: 204 No Content
[AUD] download_format_segment 320: Status: 204 No Content
[VID] download_format_segment 320: Status: 200 OK
[AUD] download_format_segment 320: Status: 200 OK
[AUD] joining segment 321
[VID] download_format_segment 321: Status: 204 No Content
[AUD] download_format_segment 321: Status: 204 No Content
[VID] download_format_segment 321: Status: 200 OK
[AUD] download_format_segment 321: Status: 200 OK
ajayalag1974 commented 2 years ago

UPDATE: So i tried debugging after getting some understanding of rust language & your code, in layman terms it turns out that in your code segment bytes were being sent by sender and receiver was not able to properly handle it (write bytes via writer) and was stucked and contantly gettting timed out.

Relevant Sender code:

tx.send(SegmentBytes::More(vec_rc.clone()))
.await
.map_err(|_| YoutubelinkError::SegmentDataSendError)?;

Relevant Receiver code line:


let out_segment_bytes = rx.recv().await;

match out_segment_bytes { None => { // Sender channel dropped break; } Some(SegmentBytes::EOF) => { stderr!(">>> received EOF \n")?; break; } Some(SegmentBytes::More(bytes)) => { stderr!(">>> received bytes \n")?; for out in txbufs.iter_mut() { //stderr!("x ")?; // looks like with youtube we can't skip bytes... // :( if out.reliable { out.tx .send(bytes.clone()) .await .maperr(|| YoutubelinkError::SegmentJoinSendError)?; } else { // non-blocking let _r = out.tx.try_send(bytes.clone()); } } } }


> Writer code which get stucks while writing bytes sent by above Receiver (out.writer.write_all):

async fn copy_channel_to_out( mut rxbuf: Receiver<Rc<Vec>>, out: &mut AsyncOutput, ) -> Result<(), anyhow::Error> { loop { // Give some time to other tasks tokio::task::yield_now().await;

    // We'll receive from channel
    // in the future
    let f = rxbuf.recv();

    let once_msg: Option<Option<Rc<Vec<u8>>>> = f.now_or_never();
    let msg: Option<Rc<Vec<u8>>>;
    match once_msg {
        // Received instantly
        Some(m) => {
            msg = m;
        }
        None => {
            out.writer.flush().await?;
            //stderr!("flushed")?;

            msg = rxbuf.recv().await;
        }
    }

    match msg {
        Some(bytes_vec) => {
            //stderr!("+ ")?;
            out.writer.write_all(&bytes_vec).await?;
        }
        // None from .recv()
        // because channel is closed
        None => {
            break;
        }
    }
}
Ok(())

}

7ERr0r commented 2 years ago

Hi, video gets stuck probably because of ffplay, you need to transcode container to mpegts instead of FLV. It was a little hard to do this automatically, but the command is generally:

  1. setup ffmpeg TCP proxy ffmpeg -listen 1 -i "tcp://127.0.0.1:5000" -c:v copy -c:a copy -f mpegts tcp://127.0.0.1:5001 ffmpeg -listen 1 -i "tcp://127.0.0.1:6000" -c:v copy -c:a copy -f mpegts tcp://127.0.0.1:6001

  2. run ffplay audio: ffplay -fflags nobuffer -flags low_delay -af volume=0.9 -x 1280 -y 720 -listen 1 -i tcp://127.0.0.1:6001 video: ffplay -x 1280 -y 720 -probesize 32 -sync ext -af volume=0.3 -vf setpts=0.5*PTS -listen 1 -i "tcp://127.0.0.1:5001"

  3. run Rust program cargo run --release -- --url https://www.youtube.com/watch?v=RTpWYWIfP7Y -f -v "tcp://127.0.0.1:5000" -a "tcp://127.0.0.1:6000"

Something like this... you need at least 3 terminals to watch video with lowest latency. Some live videos are in mpegts by default so it doesn't get stuck tho.

7ERr0r commented 2 years ago

Well the Rust program should change the container to mpegts

7ERr0r commented 2 years ago

Fixed in v0.2