Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] GStreamer sample #1972

Merged
merged 7 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ jobs:
- name: Install dependencies
shell: powershell
run: |
choco install pkgconfiglite
choco install gstreamer --version=1.16.3
choco install gstreamer-devel --version=1.16.3
curl.exe -o C:\tools\pthreads-w32-2-9-1-release.zip ftp://sourceware.org/pub/pthreads-win32/pthreads-w32-2-9-1-release.zip
Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,14 @@ To run:
./samples/kvsWebrtcClientViewerGstSample <channelName> <mediaType>
```

##### Known issues:
Our GStreamer samples leverage [MatroskaMux](https://gstreamer.freedesktop.org/documentation/matroska/matroskamux.html?gi-language=c) to receive media from its peer and save it to a file. However, MatroskaMux is designed for scenarios where the media's format remains constant throughout streaming. When the media's format changes mid-streaming (referred to as "caps changes"), MatroskaMux encounters limitations, its behavior cannot be predicted and it may be unable to handle these changes, resulting in an error message like:

```shell
matroskamux matroska-mux.c:1134:gst_matroska_mux_video_pad_setcaps:<mux> error: Caps changes are not supported by Matroska
```
To address this issue, users need to adapt the pipeline to utilize components capable of managing dynamic changes in media formats. This might involve integrating different muxers or customizing the pipeline to handle caps changes effectively.

#### Sample: Generating sample frames

##### H264
Expand All @@ -325,12 +333,12 @@ gst-launch-1.0 videotestsrc pattern=ball num-buffers=1500 ! timeoverlay ! videoc

###### ADTS LC
```shell
gst-launch-1.0 audiotestsrc num-buffers=1500 ! audioconvert ! audioresample ! faac ! capsfilter caps=audio/mpeg,mpegversion=4,stream-format=adts,base-profile=lc,channels=2,rate=48000 ! multifilesink location="sample-%03d.aac" index=1
gst-launch-1.0 audiotestsrc num-buffers=1500 ! audioconvert ! audioresample ! faac ! capsfilter caps=audio/mpeg,mpegversion=4,stream-format=adts,base-profile=lc,channels=2,rate=16000 ! multifilesink location="sample-%03d.aac" index=1
```

###### RAW LC
```shell
gst-launch-1.0 audiotestsrc num-buffers=1500 ! audioconvert ! audioresample ! faac ! capsfilter caps=audio/mpeg,mpegversion=4,stream-format=raw,base-profile=lc,channels=2,rate=44100 ! multifilesink location="sample-%03d.aac" index=1
gst-launch-1.0 audiotestsrc num-buffers=1500 ! audioconvert ! audioresample ! faac ! capsfilter caps=audio/mpeg,mpegversion=4,stream-format=raw,base-profile=lc,channels=2,rate=16000 ! multifilesink location="sample-%03d.aac" index=1
```

### Viewing Master Samples
Expand Down
1 change: 1 addition & 0 deletions samples/Common.c
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,7 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE
pSampleConfiguration->trickleIce = trickleIce;
pSampleConfiguration->useTurn = useTurn;
pSampleConfiguration->enableSendingMetricsToViewerViaDc = FALSE;
pSampleConfiguration->receiveAudioVideoSource = NULL;

pSampleConfiguration->channelInfo.version = CHANNEL_INFO_CURRENT_VERSION;
pSampleConfiguration->channelInfo.pChannelName = channelName;
Expand Down
68 changes: 40 additions & 28 deletions samples/GstAudioVideoReceiver.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
#include <gst/app/app.h>
#include <gst/app/gstappsink.h>

static UINT64 presentationTsIncrement = 0;
static BOOL eos = FALSE;

// This function is a callback for the transceiver for every single video frame it receives
// It writes these frames to a buffer and pushes it to the `appsrcVideo` element of the
// GStreamer pipeline created in `receiveGstreamerAudioVideo`. Any logic to modify / discard the frames would go here
Expand All @@ -16,22 +19,28 @@ VOID onGstVideoFrameReady(UINT64 customData, PFrame pFrame)
CHK_ERR(appsrcVideo != NULL, STATUS_NULL_ARG, "appsrcVideo is null");
CHK_ERR(pFrame != NULL, STATUS_NULL_ARG, "Video frame is null");

buffer = gst_buffer_new_allocate(NULL, pFrame->size, NULL);
CHK_ERR(buffer != NULL, STATUS_NULL_ARG, "Buffer allocation failed");
if (!eos) {
buffer = gst_buffer_new_allocate(NULL, pFrame->size, NULL);
CHK_ERR(buffer != NULL, STATUS_NULL_ARG, "Buffer allocation failed");

DLOGV("Video frame size: %d, presentationTs: %llu", pFrame->size, presentationTsIncrement);

GST_BUFFER_DTS(buffer) = presentationTsIncrement;
GST_BUFFER_PTS(buffer) = presentationTsIncrement;
GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale(1, GST_SECOND, DEFAULT_FPS_VALUE);
niyatim23 marked this conversation as resolved.
Show resolved Hide resolved
presentationTsIncrement += gst_util_uint64_scale(1, GST_SECOND, DEFAULT_FPS_VALUE);

DLOGV("Frame size: %d, presentationTs: %llu", pFrame->size, pFrame->presentationTs);
GST_BUFFER_PTS(buffer) = pFrame->presentationTs;
GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale(1, GST_SECOND, DEFAULT_FPS_VALUE);
if (gst_buffer_fill(buffer, 0, pFrame->frameData, pFrame->size) != pFrame->size) {
DLOGE("Buffer fill did not complete correctly");
if (gst_buffer_fill(buffer, 0, pFrame->frameData, pFrame->size) != pFrame->size) {
DLOGE("Buffer fill did not complete correctly");
gst_buffer_unref(buffer);
return;
}
g_signal_emit_by_name(appsrcVideo, "push-buffer", buffer, &ret);
if (ret != GST_FLOW_OK) {
DLOGE("Error pushing buffer: %s", gst_flow_get_name(ret));
}
gst_buffer_unref(buffer);
return;
}
g_signal_emit_by_name(appsrcVideo, "push-buffer", buffer, &ret);
if (ret != GST_FLOW_OK) {
DLOGE("Error pushing buffer: %s", gst_flow_get_name(ret));
}
gst_buffer_unref(buffer);

CleanUp:
return;
Expand All @@ -50,25 +59,27 @@ VOID onGstAudioFrameReady(UINT64 customData, PFrame pFrame)
CHK_ERR(appsrcAudio != NULL, STATUS_NULL_ARG, "appsrcAudio is null");
CHK_ERR(pFrame != NULL, STATUS_NULL_ARG, "Audio frame is null");

buffer = gst_buffer_new_allocate(NULL, pFrame->size, NULL);
CHK_ERR(buffer != NULL, STATUS_NULL_ARG, "Buffer allocation failed");
if (!eos) {
buffer = gst_buffer_new_allocate(NULL, pFrame->size, NULL);
CHK_ERR(buffer != NULL, STATUS_NULL_ARG, "Buffer allocation failed");

DLOGV("Audio Frame size: %d, presentationTs: %llu", pFrame->size, pFrame->presentationTs);
GST_BUFFER_PTS(buffer) = pFrame->presentationTs;
DLOGV("Audio frame size: %d, presentationTs: %llu", pFrame->size, presentationTsIncrement);

// Recalculate the byte-rate if not using the default values
GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale(pFrame->size, GST_SECOND, DEFAULT_AUDIO_OPUS_BYTE_RATE);
if (gst_buffer_fill(buffer, 0, pFrame->frameData, pFrame->size) != pFrame->size) {
DLOGE("Buffer fill did not complete correctly");
GST_BUFFER_DTS(buffer) = presentationTsIncrement;
GST_BUFFER_PTS(buffer) = presentationTsIncrement;
GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale(pFrame->size, GST_SECOND, DEFAULT_AUDIO_OPUS_BYTE_RATE);

if (gst_buffer_fill(buffer, 0, pFrame->frameData, pFrame->size) != pFrame->size) {
DLOGE("Buffer fill did not complete correctly");
gst_buffer_unref(buffer);
return;
}
g_signal_emit_by_name(appsrcAudio, "push-buffer", buffer, &ret);
if (ret != GST_FLOW_OK) {
DLOGE("Error pushing buffer: %s", gst_flow_get_name(ret));
}
gst_buffer_unref(buffer);
return;
}
g_signal_emit_by_name(appsrcAudio, "push-buffer", buffer, &ret);
if (ret != GST_FLOW_OK) {
DLOGE("Error pushing buffer: %s", gst_flow_get_name(ret));
}
gst_buffer_unref(buffer);

CleanUp:
return;
}
Expand All @@ -78,6 +89,7 @@ VOID onGstAudioFrameReady(UINT64 customData, PFrame pFrame)
VOID onSampleStreamingSessionShutdown(UINT64 customData, PSampleStreamingSession pSampleStreamingSession)
{
(void) (pSampleStreamingSession);
eos = TRUE;
GstElement* pipeline = (GstElement*) customData;
gst_element_send_event(pipeline, gst_event_new_eos());
}
Expand Down
1 change: 0 additions & 1 deletion samples/kvsWebRTCClientMasterGstSample.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,6 @@ INT32 main(INT32 argc, CHAR* argv[])

pSampleConfiguration->videoSource = sendGstreamerAudioVideo;
pSampleConfiguration->mediaType = SAMPLE_STREAMING_VIDEO_ONLY;
pSampleConfiguration->receiveAudioVideoSource = receiveGstreamerAudioVideo;
niyatim23 marked this conversation as resolved.
Show resolved Hide resolved

#ifdef ENABLE_DATA_CHANNEL
pSampleConfiguration->onDataChannel = onDataChannel;
Expand Down
Loading