0

I want to build an application on gstreamer. This application must show video and audio same time and it can be record audio and video on ".mp4" file. Application has record button and if user clicks this button, record must start or stop.

So this is my pipeline:

Pipeline has 5 different bins.

1 - videosrcbin = v4l2src ! video/x-raw, width=640, height=480 ! videoconvert ! tee name=videoTee ! queue ! autovideosink

2- audiosrcbin = autoaudiosrc name=audiosrc ! audioconvert ! tee name=audioTee ! queue ! autoaudiosink

3- videorecordbin = queue name="videoQueue" ! x264enc name="encoder" tune=zerolatency bitrate=1000 key-int-max=30 ! video/x-h264, profile=constrained-baseline ! queue

4- audiorecordbin = queue name="audioQueue" ! opusenc name="encoder" ! audio/x-opus, profile=constrained-baseline ! queue

5- recordbin = mp4mux name=recordMux ! filesink name="recordFileSink" sync=false async=false location="x%1.mp4"

This is my start recording function:

PlayerResult Player::startRecording() {

    _recordBin = createRecordBin();
    _recordBinVideo = createRecordBinForVideo();
    _recordBinAudio = createRecordBinForAudio();

    gst_bin_add_many(GST_BIN(GST_PIPELINE_CAST(_pipeline)), _recordBin, NULL);
    gst_bin_add_many(GST_BIN(_recordBin), _recordBinVideo, _recordBinAudio, NULL);

    gst_element_sync_state_with_parent (_recordBin);
    gst_element_sync_state_with_parent (_recordBinVideo);
    gst_element_sync_state_with_parent (_recordBinAudio);

    GstElement* videoTee = gst_bin_get_by_name (GST_BIN(_videoSrcBin), "videoTee");
    GstElement* audioTee = gst_bin_get_by_name (GST_BIN(_audioSrcBin), "audioTee");
    GstElement* muxer = gst_bin_get_by_name (GST_BIN(_recordBin), "recordMux");
    GstElement* videoQueue = gst_bin_get_by_name (GST_BIN(_recordBinVideo), "videoQueue");
    GstElement* audioQueue = gst_bin_get_by_name (GST_BIN(_recordBinAudio), "audioQueue");

    if(!videoTee || !audioTee || !muxer || !videoQueue || !audioQueue) {
        qInfo("Element not found !");
        return ElementCreateError;
    }
    _videoTeeSrc = gst_element_get_request_pad (videoTee, "src_%u");
    _audioTeeSrc = gst_element_get_request_pad (audioTee, "src_%u");

    GstPad* videoQueueSink = gst_element_get_static_pad(videoQueue, "sink");
    GstPad* audioQueueSink = gst_element_get_static_pad(audioQueue, "sink");


    if(!gst_element_link_pads (videoTee, GST_OBJECT_NAME(_videoTeeSrc), _recordBinVideo,GST_OBJECT_NAME(videoQueueSink))) {
        qInfo("Error on linking video with record bin!");
        return ElementLinkError;
    }
    if(!gst_element_link_pads (audioTee, GST_OBJECT_NAME(_audioTeeSrc), _recordBinAudio,GST_OBJECT_NAME(audioQueueSink))) {
        qInfo("Error on linking audio with record bin!");
        return ElementLinkError;
    }

    if(!gst_element_link(_recordBinVideo, muxer) || !gst_element_link(_recordBinAudio, muxer)) {
        qInfo("Error on linking muxers");
        return ElementLinkError;
    }

    videoRecordSinkPad = gst_pad_get_peer (_videoTeeSrc);
    audioRecordSinkPad = gst_pad_get_peer (_audioTeeSrc);

    g_object_unref (videoTee);
    g_object_unref (audioTee);
    g_object_unref (videoQueueSink);
    g_object_unref (audioQueueSink);
    g_object_unref (muxer);
    _isRecording = true;
    return Success;
}

My stop function:

void Player::stop() {
    GstPad *videoTeeSrc, *audioTeeSrc;

    videoTeeSrc = gst_pad_get_peer(videoRecordSinkPad);
    audioTeeSrc = gst_pad_get_peer(audioRecordSinkPad);

    gst_pad_add_probe(videoTeeSrc, GST_PAD_PROBE_TYPE_IDLE, stopRecordingProbeForVideo,
                      this, NULL);
    gst_pad_add_probe(audioTeeSrc, GST_PAD_PROBE_TYPE_IDLE, stopRecordingProbeForAudio,
                      this, NULL);

    g_object_unref (videoTeeSrc);
    g_object_unref (audioTeeSrc);
}
GstPadProbeReturn Player::stopRecordingProbeForVideo(GstPad *tee_src, GstPadProbeInfo *info, gpointer data) {

    Player* player = static_cast<Player*>(data);
    GstElement *tee, *filesink;
    GstPad *filesink_sink;
    if(!player->videoRecordSinkPad) {
        qInfo("Sink pads not found");
        return GST_PAD_PROBE_PASS;
    }


    gst_pad_unlink (tee_src, player->videoRecordSinkPad);

    filesink = gst_bin_get_by_name_recurse_up (GST_BIN_CAST (player->_recordBin),
                                               "recordFileSink");
    g_assert (filesink);
    filesink_sink = gst_element_get_static_pad (filesink, "sink");
    g_assert (filesink_sink);

    gst_pad_add_probe(filesink_sink, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
                      filesinkEosProbe, player, NULL);
    gst_pad_send_event (player->videoRecordSinkPad, gst_event_new_eos ());
    return GST_PAD_PROBE_DROP;
}
GstPadProbeReturn Player::stopRecordingProbeForAudio(GstPad *tee_src, GstPadProbeInfo *info, gpointer data) {

    Player* player = static_cast<Player*>(data);

    if(!player->videoRecordSinkPad || !player->audioRecordSinkPad) {
        qInfo("Sink pads not found");
        return GST_PAD_PROBE_PASS;
    }
    gst_pad_unlink (tee_src, player->videoRecordSinkPad);
    gst_pad_send_event (player->audioRecordSinkPad, gst_event_new_eos ());

    return GST_PAD_PROBE_DROP;
}
GstPadProbeReturn Player::filesinkEosProbe(GstPad *tee_src, GstPadProbeInfo *info, gpointer data) {
    qInfo("Here !");
    Player* player = static_cast<Player*>(data);
    GstElement *recordingBin, *recordingBin2;
    GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);

    if (GST_EVENT_TYPE (event) != GST_EVENT_EOS) {
        return GST_PAD_PROBE_OK;
    }

    g_idle_add_full (G_PRIORITY_DEFAULT, releaseRecordingBin, player,
                     NULL);


    return GST_PAD_PROBE_REMOVE;
}
gboolean Player::releaseRecordingBin(gpointer data) {
    Player* player = static_cast<Player*>(data);
    player->_recordBinVideo->setState(QGst::StateNull);
    player->_recordBinAudio->setState(QGst::StateNull);
    player->_recordBin->setState(QGst::StateNull);
    player->_recordBin.clear();
    player->_recordBinVideo.clear();
    player->_recordBinAudio.clear();
    player->_isRecording = false;
}

This function works good but how can I stop recording. I am sending EOS signals both video and audio encoders. Then when eos signals come on filesink, I am removing all record elements from pipeline and memory.

I am clicking record button on my app and sometimes my app is crashing. When I press my record button the recording must be saved on seperate file. If I press n times record button, the program must save n/2 different recordings. But program stucks randomly and some threads freezing. Buttons and display can't be work.I guess it is a deadlock. How can I resolve this problem ?

Thanks..

0 Answers0