scottlamb / retina

High-level RTSP multimedia streaming library, in Rust
https://crates.io/crates/retina
Apache License 2.0
237 stars 47 forks source link

mp4 example: Ignoring h264 video stream because it's unsupported #43

Closed lattice0 closed 2 years ago

lattice0 commented 2 years ago

On the cargo run example, I get:

     Running `target/debug/examples/client mp4 --url 'rtsp://192.168.1.22:10554/tcp/av0_0' --username admin --password 123456 out.mp4`
W20211130 01:57:55.777 main retina::codec::h264] Ignoring bad H.264 format-specific-params "packetization-mode=1;profile-level-id=00f004;sprop-parameter-sets=6QDwBE/LCAAAH0gAB1TgIAAAAAA=,AAAAAA==": bad sprop-parameter-sets: bad NAL header e9
I20211130 01:57:55.779 main client::mp4] Ignoring h264 video stream because it's unsupported
I20211130 01:57:55.779 main client::mp4] No suitable video stream found
I20211130 01:57:55.781 main client::mp4] Ignoring pcma audio stream because it can't be placed into a .mp4 file without transcoding
I20211130 01:57:55.781 main client::mp4] No suitable audio stream found
E20211130 01:57:55.782 main client] Fatal: Exiting because no video or audio stream was selected; see info log messages above

from https://github.com/scottlamb/retina/blob/cd841b9f80f1d0dbd7226ad43c3023e4c6e84c40/examples/client/mp4.rs#L724

On my app, I get just this first video frame, and then nothing more:

video frame: VideoFrame { timestamp: 2022 (mod-2^32: 2022), npt 0.000, start_ctx: PacketContext(Tcp { msg_ctx: RtspMessageContext { pos: 868, received_wall: WallTime(Timespec { sec: 1638237968, nsec: 431245911 }), received: Instant { tv_sec: 83828, tv_nsec: 228186887 } }, channel_id: 0 }), end_ctx: PacketContext(Tcp { msg_ctx: RtspMessageContext { pos: 29964, received_wall: WallTime(Timespec { sec: 1638237968, nsec: 439222146 }), received: Instant { tv_sec: 83828, tv_nsec: 236162701 } }, channel_id: 0 }), loss: 0, new_parameters: Some(VideoParameters { rfc6381_codec: "avc1.4D0028", pixel_dimensions: (1920, 1080), pixel_aspect_ratio: None, frame_rate: Some((2002, 60060)), extra_data: Length: 35 (0x23) bytes
    0000:   01 4d 00 28  ff e1 00 14  67 4d 00 28  e9 00 f0 04   .M.(....gM.(....
    0010:   4f cb 08 00  00 1f 48 00  07 54 e0 20  01 00 04 68   O.....H..T. ...h
    0020:   ea 8f 20                                             ..  }), is_random_access_point: true, is_disposable: false, data_len: 30023 }

on the line

tokio::select! {
                                    item = session.next() => {
                                        match item {
                                            Some(Ok(CodecItem::MessageFrame(m))) => {
                                                info!("{}: {}\n", &m.timestamp, std::str::from_utf8(&m.data[..]).unwrap());
                                            },
                                            Some(Ok(CodecItem::VideoFrame(v))) => {
                                                info!("video frame: {:?}", v);

packet capture of cargo run example sent via email

lattice0 commented 2 years ago

Actually, it works on my app. I don't receive just one packet. Turns out I was doing this:

Some(Ok(CodecItem::VideoFrame(v))) => {
                                                info!("video frame: {:?}", v);

                                                let mut nal_bytes = Vec::new();
                                                avcc_to_annex_b(&v.data(), &mut nal_bytes);
                                                let packet = Box::new(RetinaEncodedPacket {
                                                    video_frame: v,
                                                    nal_bytes: nal_bytes
                                                });
                                                on_produce(packet);

                                            }

and it got caught in a loop. Probably something wrong with my avcc_to_annex_b implementation that I'm testing.

So the only problem is in the cargo run example

scottlamb commented 2 years ago

Ahh, basically I missed in #42 a place where the example was checking for a supported codec by having the parameters. It needs to be updated to not expect them to be present right away.