How to decode a ts segment in a u8 vec from appsrc - rust

Hi, I have been trying to feed a u8 vec coming my application will read from a RabbitMQ into an appsrc to transcode it.

I am trying a simple pipeline like the following without decode to test it.

gst-launch-1.0 filesrc location=dip.ts ! tsdemux name=demux demux. ! h264parse ! mpegtsmux ! filesink location=pp.ts

I wrote the following code to build the pipeline in rust. However I keep getting “Internal data stream error”.

fn create_pipeline() -> Result<gst::Pipeline, Error> {
    gst::init()?;

    let pipeline = gst::Pipeline::default();

    let video_info = &gst::Caps::builder("video/x-h264")
        .field("stream-format", &"byte-stream")
        .build();

    let appsrc = gst_app::AppSrc::builder()
        .caps(video_info)
        .format(gst::Format::Time)
        .build();

    // gst-launch-1.0 filesrc location=dip.ts ! tsdemux name=demux demux. ! h264parse ! mpegtsmux ! filesink location=pp.ts
    let tsdemux = gst::ElementFactory::make("tsdemux").build()?;
    let h264parse = gst::ElementFactory::make("h264parse").build()?;
    let mpegtsmux = gst::ElementFactory::make("mpegtsmux").build()?;
    let filesink = gst::ElementFactory::make("multifilesink").build()?;
    filesink.set_property("location", "%d.ts");
    filesink.set_property("post-messages", true);
    filesink.set_property_from_str("next-file", "discont");

    let video_sink_pad = h264parse.static_pad("sink").expect("could not get sink pad from h264parse");

    pipeline.add_many(&[appsrc.upcast_ref(), &tsdemux, h264parse.upcast_ref(), &mpegtsmux, &filesink])?;
    gst::Element::link_many(&[appsrc.upcast_ref(), &tsdemux])?;

    tsdemux.connect_pad_added(move |_src, src_pad| {
        let is_video = if src_pad.name().starts_with("video") {
            true
        } else {
            false
        };

        let connect_demux = || -> Result<(), Error> {
            src_pad.link(&video_sink_pad).expect("failed to link tsdemux.video->h264parse.sink");
            println!("linked tsdemux->h264parse");
            Ok(())
        };

        if is_video {
            match connect_demux() {
                Ok(_) => println!("tsdemux->h264 connected"),
                Err(e) => println!("could not connect tsdemux->h264parse e:{}", e),
            }
        }
    });


    gst::Element::link_many(&[&h264parse.upcast_ref(), &mpegtsmux, &filesink])?;

     appsrc.set_callbacks(
         gst_app::AppSrcCallbacks::builder()
             .need_data(move |appsrc, _| {
                 println!("getting the file");
                 let mut file = File::open("./dip.ts").unwrap();
                 let mut buffer = Vec::new();
                 match file.read_to_end(&mut buffer) {
                     Ok(_) => {
                         println!("finished reading bytes from file len={}", buffer.len());
                     }
                     Err(e) => {
                         println!("error reading file: {}", e);
                     }
                 };
                 let gst_buffer = gst::Buffer::from_slice(buffer);
                 println!("buffer size of teh generated gst_buffer={}", gst_buffer.size());
                 let _ = appsrc.push_buffer(gst_buffer);
             }).build(),
     );

    Ok(pipeline)

}

Is it because appsrc is not able to handle the buffer size? If so how do I divide it into chunks in a byte-stream?

That shouldn’t be the problem, but you can simply chunk the buffers in any way you want here. The tsdemux would parse them as needed.

That’s most likely because you set video/x-h264 as caps on the MPEG-TS stream. That’s wrong. Either don’t set any caps at all (like in the gst-launch-1.0 case), or set video/mpegts, systemstream=true.

Thanks a lot @slomo ! That fixed the issue.

1 Like