diff options
| -rw-r--r-- | Readme.md | 47 | ||||
| -rw-r--r-- | s3_client.cpp | 44 | ||||
| -rw-r--r-- | s3_client.h | 2 | ||||
| -rw-r--r-- | s3_worker.c | 2 |
4 files changed, 91 insertions, 4 deletions
@@ -1,7 +1,48 @@ # EZLive: Self-hosted Serverless Livestream -(Still work-in-progress) - EZLive is a minimal self-hosted livestream solution built on top of S3-compatible object storage. -It runs a local RTMP server, receive live video, turns it into HLS segments (.m3u8 + .ts) and serves them as static files through S3 or a CDN. No dedicated streaming server is required — everything runs serverless.
\ No newline at end of file +It runs a local RTMP server, receive live video, turns it into HLS segments (.m3u8 + .ts) and serves them as static files through any S3-compatible OSS. No dedicated streaming server is required — everything runs serverlessly. Then you can easily setup a HTML5 HLS player to watch the stream. + +# Build + +Install dependencies: + +- FFMpeg (libavformat, libavutil, libavcodec) +- AWS C++ SDK (libaws-cpp-sdk-core, libaws-cpp-sdk-s3) + +Build: + + make + + +# Usage + +Setup a S3-compatible OSS bucket, for example, Cloudflare R2, AWS S3, Minio, DigitalOcean, etc. + +Then create a config file `config`: + +``` +listening_addr=127.0.0.1 +listening_port=1935 +bucket=YOUR_BUCKET_NAME +endpoint=https://your-oss.com +s3_path=ezlive/ +access_key=YOUR_S3_ACCESS_KEY +secret_key=YOUR_S3_SECRET_KEY +region=auto +``` + +In the dashboard of your OSS cloud provider, add the domain name of your web HLS player to CORS setting. If you don't know how to setup a web HLS player, just add `https://mistivia.github.io`. + +Start EZLive: + +``` +./ezlive +``` + +Open OBS, streaming to `rtmp://127.0.0.1/live`, no streaming key needed. + +Then use a HLS player to load `https://YOUR_BUCKET_NAME.our-oss.com/ezlive/stream.m3u8` to watch the stream. + +If you don't know how to setup a HLS player, then make sure you have added `https://mistivia.github.io` in your OSS's CORS setting, then open `https://mistivia.github.io/ezlive#https://YOUR_BUCKET_NAME.our-oss.com/ezlive/stream.m3u8`. diff --git a/s3_client.cpp b/s3_client.cpp index 4076b1c..668e902 100644 --- a/s3_client.cpp +++ b/s3_client.cpp @@ -8,7 +8,9 @@ #include <aws/s3/S3Client.h> #include <aws/s3/model/PutObjectRequest.h> #include <aws/s3/model/DeleteObjectRequest.h> +#include <aws/s3/model/DeleteObjectsRequest.h> #include <aws/core/auth/AWSCredentials.h> +#include <aws/s3/model/ListObjectsV2Request.h> #include "ezlive_config.h" @@ -76,4 +78,46 @@ void S3Client_delete(const char *object_name) { } else { fprintf(stdout, "Successfully deleted the object: %s\n", object_name); } +} + +void S3Client_clear() { + Aws::S3::Model::ListObjectsV2Request list_req; + list_req.WithBucket(ezlive_config->bucket).WithPrefix(ezlive_config->s3_path); + + auto list_outcome = s3client->ListObjectsV2(list_req); + if (!list_outcome.IsSuccess()) { + fprintf(stderr, "ListObjectsV2 error: %s\n", + list_outcome.GetError().GetMessage().c_str()); + return; + } + + Aws::Vector<Aws::S3::Model::ObjectIdentifier> objects_to_delete; + + for (const auto& obj : list_outcome.GetResult().GetContents()) { + auto key = obj.GetKey(); + if (key.size() >= 3 && key.substr(key.size() - 3) == ".ts") { + Aws::S3::Model::ObjectIdentifier oid; + oid.SetKey(key); + objects_to_delete.push_back(oid); + printf("Marking for delete: %s\n", key.c_str()); + } + } + if (!objects_to_delete.empty()) { + Aws::S3::Model::DeleteObjectsRequest del_req; + del_req.WithBucket(ezlive_config->bucket) + .WithDelete(Aws::S3::Model::Delete().WithObjects(objects_to_delete)); + + auto del_outcome = s3client->DeleteObjects(del_req); + if (!del_outcome.IsSuccess()) { + std::cerr << "DeleteObjects error: " + << del_outcome.GetError().GetMessage() << std::endl; + return; + } else { + std::cout << "Deleted " + << del_outcome.GetResult().GetDeleted().size() + << " objects." << std::endl; + } + } else { + std::cout << "No .ts files found. No need to clear." << std::endl; + } }
\ No newline at end of file diff --git a/s3_client.h b/s3_client.h index 43d4208..f42e549 100644 --- a/s3_client.h +++ b/s3_client.h @@ -11,6 +11,8 @@ void S3Client_put(const char *filename, const char *object_name); void S3Client_delete(const char *object_name); +void S3Client_clear(); + #ifdef __cplusplus } #endif diff --git a/s3_worker.c b/s3_worker.c index a6ae2ab..6482224 100644 --- a/s3_worker.c +++ b/s3_worker.c @@ -21,7 +21,7 @@ void exec_s3_task(void *vtask) { snprintf(obj_name_buf, 255, "%s%s", ezlive_config->s3_path, task->remote_name); S3Client_delete(obj_name_buf); } else if (task->task_type == kClearTask) { - // TODO + S3Client_clear(); } else { fprintf(stderr, "unknown task type.\n"); } |
