Skip to content

Commit e589df7

Browse files
committed
Adding sample checks
1 parent 9e057c2 commit e589df7

File tree

3 files changed

+156
-26
lines changed

3 files changed

+156
-26
lines changed

.github/workflows/samples.yml

Lines changed: 129 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,13 @@ jobs:
2121
args: -f sample.mp4
2222
- name: kvs_gstreamer_file_uploader_sample
2323
args: sample.mp4 0 audio-video
24-
# - name: kvs_gstreamer_multistream_sample
25-
# args: ""
2624
- name: kvs_gstreamer_sample
2725
args: sample.mp4
2826
- name: kvssink_gstreamer_sample
2927
args: sample.mp4
3028
runner:
31-
- id: macos-latest
32-
image: macos-latest
29+
- id: macos-13
30+
image: macos-13
3331

3432
- id: ubuntu-22.04
3533
image: ubuntu-latest
@@ -50,8 +48,9 @@ jobs:
5048

5149
env:
5250
AWS_KVS_LOG_LEVEL: 2
53-
KVS_DEBUG_DUMP_DATA_FILE_DIR: ./debug_output
51+
KVS_DEBUG_DUMP_DATA_FILE_DIR: ${{ github.workspace }}/build/debug_output
5452
DEBIAN_FRONTEND: noninteractive
53+
GST_PLUGIN_PATH: ${{ github.workspace }}/build
5554

5655
permissions:
5756
id-token: write
@@ -92,17 +91,14 @@ jobs:
9291
9392
- name: Build samples (Windows)
9493
if: runner.os == 'Windows'
95-
shell: cmd
9694
run: |
97-
@echo on
98-
set PATH=%PATH%;C:\Strawberry\perl\site\bin;C:\Strawberry\perl\bin;C:\Strawberry\c\bin;C:\Program Files\NASM;D:\a\amazon-kinesis-video-streams-producer-c\amazon-kinesis-video-streams-producer-c\open-source\lib;D:\a\amazon-kinesis-video-streams-producer-c\amazon-kinesis-video-streams-producer-c\open-source\bin
95+
$env:Path += ';C:\Strawberry\perl\site\bin;C:\Strawberry\perl\bin;C:\Strawberry\c\bin;C:\Program Files\NASM;D:\producer\open-source\local\lib;D:\producer\open-source\local\bin'
96+
mkdir D:\producer
97+
Move-Item -Path "D:\a\amazon-kinesis-video-streams-producer-sdk-cpp\amazon-kinesis-video-streams-producer-sdk-cpp\*" -Destination "D:\producer"
98+
cd D:\producer
9999
git config --system core.longpaths true
100-
"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
101-
mkdir build
102-
cd build
103-
cmake -G "NMake Makefiles" -DBUILD_GSTREAMER_PLUGIN=ON -DPKG_CONFIG_EXECUTABLE="D:\\gstreamer\\1.0\\msvc_x86_64\\bin\\pkg-config.exe" ..
104-
nmake
105-
mkdir "%KVS_DEBUG_DUMP_DATA_FILE_DIR%"
100+
dir
101+
.github\build_windows.bat
106102
107103
- name: Configure AWS Credentials
108104
uses: aws-actions/configure-aws-credentials@v4
@@ -114,9 +110,6 @@ jobs:
114110

115111
- name: Run ${{ matrix.sample.name }} (Linux & Mac)
116112
if: runner.os == 'Linux' || runner.os == 'macOS'
117-
env:
118-
GST_PLUGIN_PATH: ${{ github.workspace }}/build
119-
KVS_DEBUG_DUMP_DATA_FILE_DIR: ${{ github.workspace }}/build/debug_output
120113
working-directory: ./build
121114
run: |
122115
curl -fsSL -o sample.mp4 https://awsj-iot-handson.s3-ap-northeast-1.amazonaws.com/kvs-workshop/sample.mp4
@@ -125,15 +118,21 @@ jobs:
125118
- name: Run ${{ matrix.sample.name }} (Windows)
126119
if: runner.os == 'Windows'
127120
env:
128-
GST_PLUGIN_PATH: ${{ github.workspace }}/build
129-
KVS_DEBUG_DUMP_DATA_FILE_DIR: ${{ github.workspace }}/build/debug_output
130-
working-directory: ./build
121+
GST_PLUGIN_PATH: D:\producer\build
122+
KVS_DEBUG_DUMP_DATA_FILE_DIR: D:\producer\debug_output
123+
working-directory: D:\producer\build
131124
run: |
125+
# Equivalent to set -x
126+
Set-PSDebug -Trace 1
127+
132128
$env:Path += ';C:\Strawberry\perl\site\bin;C:\Strawberry\perl\bin;C:\Strawberry\c\bin;C:\Program Files\NASM;D:\producer\open-source\local\lib;D:\producer\open-source\local\bin;D:\gstreamer\1.0\msvc_x86_64\bin'
133129
130+
mkdir D:\producer\debug_output
131+
134132
Invoke-WebRequest -Uri https://awsj-iot-handson.s3-ap-northeast-1.amazonaws.com/kvs-workshop/sample.mp4 -OutFile sample.mp4
135-
$exePath = Join-Path $PWD ${{ matrix.sample.name }}
136-
& $exePath.exe demo-stream-producer-cpp-${{ matrix.runner.id }}-ci-${{ matrix.sample.name }} ${{ matrix.sample.args }}
133+
dir
134+
$exePath = Join-Path $PWD ${{ matrix.sample.name }}.exe
135+
& $exePath demo-stream-producer-cpp-${{ matrix.runner.id }}-ci-${{ matrix.sample.name }} ${{ matrix.sample.args }}
137136
138137
- name: Verify MKV dump (Mac & Linux)
139138
if: runner.os == 'Linux' || runner.os == 'macOS'
@@ -154,13 +153,13 @@ jobs:
154153
done
155154
shell: bash
156155

157-
- name: Verify MKV dump
156+
- name: Verify MKV dump (Windows)
158157
if: runner.os == 'Windows'
159158
working-directory: D:\producer\build
160159
run: |
161160
$env:Path += ";C:\Program Files\MKVToolNix"
162-
dir debug_output
163-
$mkvFiles = Get-ChildItem -Path "D:\producer\build\debug_output" -Filter *.mkv
161+
dir D:\producer\debug_output
162+
$mkvFiles = Get-ChildItem -Path "D:\producer\debug_output" -Filter *.mkv
164163
if ($mkvFiles.Count -eq 0) {
165164
Write-Error "No MKV files found in D:\producer\build\debug_output"
166165
exit 1
@@ -170,3 +169,108 @@ jobs:
170169
Write-Output "Verifying $($file.FullName) with mkvinfo (verbose and hexdump):"
171170
mkvinfo.exe -v -X "$($file.FullName)"
172171
}
172+
173+
multistream-sample:
174+
name: Multistream sample on Mac
175+
runs-on: macos-13
176+
timeout-minutes: 30
177+
178+
env:
179+
AWS_KVS_LOG_LEVEL: 2
180+
KVS_DEBUG_DUMP_DATA_FILE_DIR: ${{ github.workspace }}/build/debug_output
181+
GST_PLUGIN_PATH: ${{ github.workspace }}/build
182+
DEBIAN_FRONTEND: noninteractive
183+
184+
permissions:
185+
id-token: write
186+
contents: read
187+
188+
steps:
189+
- name: Clone repository
190+
uses: actions/checkout@v4
191+
192+
- name: Install dependencies
193+
run: |
194+
brew install gstreamer log4cplus mkvtoolnix coreutils
195+
brew install --cask docker
196+
197+
- name: Build samples
198+
run: |
199+
mkdir build && cd build
200+
mkdir -p $KVS_DEBUG_DUMP_DATA_FILE_DIR
201+
cmake .. -DBUILD_GSTREAMER_PLUGIN=ON -DBUILD_DEPENDENCIES=OFF
202+
make -j$(nproc)
203+
204+
- name: Configure AWS Credentials
205+
uses: aws-actions/configure-aws-credentials@v4
206+
with:
207+
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
208+
role-session-name: ${{ secrets.AWS_ROLE_SESSION_NAME }}
209+
aws-region: ${{ secrets.AWS_REGION }}
210+
role-duration-seconds: 10800
211+
212+
- name: Run multistream sample
213+
working-directory: ./build
214+
run: |
215+
set -x
216+
217+
open -a /Applications/Docker.app --args --unattended --accept-license
218+
echo "We are waiting for Docker to be up and running. It can take over 2 minutes..."
219+
while ! /Applications/Docker.app/Contents/Resources/bin/docker info &>/dev/null; do sleep 1; done
220+
221+
sudo ln -s ~/.docker/run/docker.sock /var/run/docker.sock
222+
223+
docker run -d --rm -it -e RTSP_PROTOCOLS=tcp -p 8554:8554 bluenviron/mediamtx:latest
224+
docker run -d --rm -it -e RTSP_PROTOCOLS=tcp -p 8555:8554 bluenviron/mediamtx:latest
225+
226+
(
227+
ffmpeg -re -f lavfi -i "testsrc=size=640x480:rate=10" -vcodec libx264 -x264-params keyint=25 -f rtsp rtsp://localhost:8554/mystream
228+
) &
229+
(
230+
ffmpeg -re -f lavfi -i "testsrc=size=640x480:rate=10" -vcodec libx264 -x264-params keyint=25 -f rtsp rtsp://localhost:8555/mystream
231+
) &
232+
233+
echo "rtsp://0.0.0.0:8554/mystream" > rtsp-urls.txt
234+
echo "rtsp://0.0.0.0:8555/mystream" >> rtsp-urls.txt
235+
236+
sleep 10
237+
gst-discoverer-1.0 rtsp://0.0.0.0:8554/mystream
238+
gst-discoverer-1.0 rtsp://0.0.0.0:8555/mystream
239+
240+
set +e # Disable exit on error for the timeout command
241+
gtimeout --preserve-status --signal=SIGINT --kill-after=15s 30s \
242+
./kvs_gstreamer_multistream_sample demo-stream-producer-cpp-macos-13-ci-kvs_gstreamer_multistream_sample rtsp-urls.txt
243+
EXIT_CODE=$?
244+
set -e # Re-enable exit on error
245+
246+
# 0: Process exited after interrupt with code 0
247+
# 1: Process exited with error code 1
248+
# 137: Process killed by SIGKILL (if the --kill-after timeout is reached)
249+
echo "Command exited with code: $EXIT_CODE"
250+
if [ $EXIT_CODE -ne 0 ]; then
251+
echo "Command did not exit gracefully after interrupt."
252+
exit 1
253+
fi
254+
255+
shell: bash
256+
257+
- name: Verify MKV dump
258+
working-directory: ./build/debug_output
259+
run: |
260+
shopt -s nullglob # Ensure globbing works correctly and avoids errors when no files are found
261+
262+
ls -tlrh
263+
mkvfiles=(*.mkv)
264+
if [ ${#mkvfiles[@]} -eq 0 ]; then
265+
echo "No MKV files found in debug_output"
266+
exit 1
267+
elif [ ${#mkvfiles[@]} -lt 2 ]; then
268+
echo "Only 1 MKV was found, but there should be at least 2"
269+
exit 1
270+
endif
271+
272+
for file in "${mkvfiles[@]}"; do
273+
echo "Verifying $file with mkvinfo (verbose and hexdump):"
274+
mkvinfo -v -X "$file"
275+
done
276+
shell: bash

samples/kvs_gstreamer_multistream_sample.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ LOGGER_TAG("com.amazonaws.kinesis.video.gstreamer");
5353
#define DEFAULT_BUFFER_SIZE (1 * 1024 * 1024)
5454
#define DEFAULT_STORAGE_SIZE (128 * 1024 * 1024)
5555
#define DEFAULT_ROTATION_TIME_SECONDS 3600
56+
#define DEFAULT_FRAME_DURATION_MS 2
5657

5758
namespace com { namespace amazonaws { namespace kinesis { namespace video {
5859

@@ -180,6 +181,7 @@ typedef struct _CustomData {
180181
// Pts of first frame
181182
map<string, uint64_t> first_pts_map;
182183
map<string, uint64_t> producer_start_time_map;
184+
map<string, uint64_t> last_dts_map;
183185
} CustomData;
184186

185187
void create_kinesis_video_frame(Frame *frame, const nanoseconds &pts, const nanoseconds &dts, FRAME_FLAGS flags,
@@ -188,6 +190,10 @@ void create_kinesis_video_frame(Frame *frame, const nanoseconds &pts, const nano
188190
frame->decodingTs = static_cast<UINT64>(dts.count()) / DEFAULT_TIME_UNIT_IN_NANOS;
189191
frame->presentationTs = static_cast<UINT64>(pts.count()) / DEFAULT_TIME_UNIT_IN_NANOS;
190192
// set duration to 0 due to potential high spew from rtsp streams
193+
194+
cout << frame->decodingTs << " DTS" << endl;
195+
cout << frame->presentationTs << " PTS" << endl;
196+
191197
frame->duration = 0;
192198
frame->size = static_cast<UINT32>(len);
193199
frame->frameData = reinterpret_cast<PBYTE>(data);
@@ -259,6 +265,12 @@ static GstFlowReturn on_new_sample(GstElement *sink, CustomData *data) {
259265

260266
buffer->pts += data->producer_start_time_map[stream_handle_key] - data->first_pts_map[stream_handle_key];
261267

268+
if (!GST_BUFFER_DTS_IS_VALID(buffer)) {
269+
buffer->dts = data->last_dts_map[stream_handle_key] + DEFAULT_FRAME_DURATION_MS * HUNDREDS_OF_NANOS_IN_A_MILLISECOND * DEFAULT_TIME_UNIT_IN_NANOS;
270+
}
271+
272+
data->last_dts_map[stream_handle_key] = buffer->dts;
273+
262274
if (false == put_frame(data->kinesis_video_stream_handles[stream_handle_key], data->frame_data_map[stream_handle_key], buffer_size, std::chrono::nanoseconds(buffer->pts),
263275
std::chrono::nanoseconds(buffer->dts), kinesis_video_flags)) {
264276
GST_WARNING("Dropped frame");
@@ -405,7 +417,8 @@ int gstreamer_init(int argc, char *argv[]) {
405417
data.frame_data_map = map<string, uint8_t*>();
406418
data.frame_data_size_map = map<string, UINT32>();
407419
data.first_pts_map = map<string, uint64_t>();
408-
data.producer_start_time_map = map<string, uint64_t>();;
420+
data.producer_start_time_map = map<string, uint64_t>();
421+
data.last_dts_map = map<string, uint64_t>();;
409422

410423
/* init GStreamer */
411424
gst_init(&argc, &argv);

src/gstreamer/gstkvssink.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,10 @@ bool put_frame(shared_ptr<KvsSinkCustomData> data, void *frame_data, size_t len,
12181218

12191219
Frame frame;
12201220
create_kinesis_video_frame(&frame, pts, dts, flags, frame_data, len, track_id, index);
1221+
1222+
cout << frame.decodingTs << " DTS" << endl;
1223+
cout << frame.presentationTs << " PTS" << endl;
1224+
12211225
bool ret = data->kinesis_video_stream->putFrame(frame);
12221226
if (data->get_metrics && ret) {
12231227
if (CHECK_FRAME_FLAG_KEY_FRAME(flags) || data->on_first_frame) {
@@ -1250,6 +1254,8 @@ gst_kvs_sink_handle_buffer (GstCollectPads * pads,
12501254
FRAME_FLAGS kinesis_video_flags = FRAME_FLAG_NONE;
12511255
GstMapInfo info;
12521256

1257+
cout << "Received DtS from GST: " << buf->dts << endl;
1258+
12531259
info.data = NULL;
12541260
// eos reached
12551261
if (buf == NULL && track_data == NULL) {
@@ -1302,6 +1308,8 @@ gst_kvs_sink_handle_buffer (GstCollectPads * pads,
13021308
goto CleanUp;
13031309
}
13041310

1311+
cout << "Received DtS from GST2: " << buf->dts << endl;
1312+
13051313
// In offline mode, if user specifies a file_start_time, the stream will be configured to use absolute
13061314
// timestamp. Therefore in here we add the file_start_time to frame pts to create absolute timestamp.
13071315
// If user did not specify file_start_time, file_start_time will be 0 and has no effect.
@@ -1313,9 +1321,12 @@ gst_kvs_sink_handle_buffer (GstCollectPads * pads,
13131321
buf->pts = buf->dts;
13141322
}
13151323
} else if (!GST_BUFFER_DTS_IS_VALID(buf)) {
1324+
cout << "In here!!" << endl;
13161325
buf->dts = data->last_dts + DEFAULT_FRAME_DURATION_MS * HUNDREDS_OF_NANOS_IN_A_MILLISECOND * DEFAULT_TIME_UNIT_IN_NANOS;
13171326
}
13181327

1328+
cout << "Received DtS from GST3: " << buf->dts << endl;
1329+
13191330
data->last_dts = buf->dts;
13201331
track_id = kvs_sink_track_data->track_id;
13211332

@@ -1358,6 +1369,8 @@ gst_kvs_sink_handle_buffer (GstCollectPads * pads,
13581369
}
13591370
}
13601371

1372+
cout << "Received DtS from GST4: " << buf->dts << endl;
1373+
13611374
put_frame(kvssink->data, info.data, info.size,
13621375
std::chrono::nanoseconds(buf->pts),
13631376
std::chrono::nanoseconds(buf->dts), kinesis_video_flags, track_id, data->frame_count);

0 commit comments

Comments
 (0)