aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fsutils.c47
-rw-r--r--fsutils.h16
-rw-r--r--main.c1
-rw-r--r--transcode_talker.c113
-rw-r--r--transcode_talker.h8
5 files changed, 176 insertions, 9 deletions
diff --git a/fsutils.c b/fsutils.c
new file mode 100644
index 0000000..0c38eaf
--- /dev/null
+++ b/fsutils.c
@@ -0,0 +1,47 @@
+#include "fsutils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void tmp_local_filename(const char *prefix, char *buf) {
+ static const char hex[] = "0123456789abcdef";
+ int prefix_len = strlen(prefix);
+ memcpy(buf, prefix, prefix_len);
+ buf = buf + prefix_len;
+ size_t i;
+ for (i = 0; i < 4; i++) {
+ unsigned char r = rand() & 0xFF;
+ buf[i * 2] = hex[r >> 4];
+ buf[i * 2 + 1] = hex[r & 0xF];
+ }
+ buf[i*2] = '\0';
+}
+
+void tmp_ts_prefix(char *buf) {
+ static const char hex[] = "0123456789abcdef";
+ size_t i;
+ for (i = 0; i < 4; i++) {
+ unsigned char r = rand() & 0xFF;
+ buf[i * 2] = hex[r >> 4];
+ buf[i * 2 + 1] = hex[r & 0xF];
+ }
+ buf[i*2] = '\0';
+}
+
+void ts_filename(const char *prefix, int num, char *buf) {
+ snprintf(buf, 256, "s%s%04d.ts", prefix, num);
+}
+
+void upload_file(const char *local, const char *remote) {
+ // TODO
+}
+
+void remove_remote(const char *remote) {
+ // TODO
+}
+
+char ** list_file() {
+ // TODO
+ return NULL;
+} \ No newline at end of file
diff --git a/fsutils.h b/fsutils.h
new file mode 100644
index 0000000..24cd5ab
--- /dev/null
+++ b/fsutils.h
@@ -0,0 +1,16 @@
+#ifndef FS_UTILS_H_
+#define FS_UTILS_H_
+
+void tmp_local_filename(const char *prefix, char *buf);
+
+void tmp_ts_prefix(char *buf);
+
+void ts_filename(const char *prefix, int num, char *buf);
+
+void upload_file(const char *local, const char *remote);
+
+void remove_remote(const char *remote);
+
+char ** list_file();
+
+#endif \ No newline at end of file
diff --git a/main.c b/main.c
index 9839ad5..f7ab273 100644
--- a/main.c
+++ b/main.c
@@ -55,6 +55,7 @@ void on_rtmp_audio(void *ctx, int64_t timestamp, char *buf, size_t size) {
}
int main() {
+ srand((unsigned) time(NULL));
MainCtx main_ctx;
RtmpCallbacks rtmp_cbs = {
.on_audio = &on_rtmp_audio,
diff --git a/transcode_talker.c b/transcode_talker.c
index 9dd9ae1..ac325ad 100644
--- a/transcode_talker.c
+++ b/transcode_talker.c
@@ -1,4 +1,5 @@
#include "transcode_talker.h"
+#include "fsutils.h"
#include "ringbuf.h"
#include <bits/pthreadtypes.h>
@@ -8,6 +9,38 @@
#include <libavutil/timestamp.h>
#include <pthread.h>
#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+void HlsList_init(HlsList *lst) {
+ lst->len = 0;
+}
+
+char * HlsList_push(HlsList *lst, char *name, double time) {
+ name = strdup(name);
+ if (lst->len < 15) {
+ lst->files[lst->len] = name;
+ lst->times[lst->len] = time;
+ lst->len++;
+ return NULL;
+ }
+ free(lst->files[0]);
+ for (int i = 0; i < 14; i++) {
+ lst->files[i] = lst->files[i+1];
+ lst->times[i] = lst->times[i+1];
+ }
+ char *ret = lst->files[0];
+ lst->files[14] = name;
+ lst->times[14] = time;
+ return ret;
+}
+
+void HlsList_clear(HlsList *lst) {
+ for (int i = 0; i < lst->len; i++) {
+ free(lst->files[i]);
+ }
+ lst->len = 0;
+}
static int wait_for_new_stream(TranscodeTalker *self) {
@@ -85,13 +118,58 @@ static void finalize_output_file(AVFormatContext *out_fmt_ctx) {
avio_closep(&out_fmt_ctx->pb);
}
avformat_free_context(out_fmt_ctx);
- // TODO: update m3u8
}
#define SEGMENT_DURATION 5
+static void update_m3u8(HlsList *lst, int last_seg) {
+ int first_seg = last_seg - lst->len + 1;
+ char out_filename[256];
+ tmp_local_filename("/tmp/ezlive", out_filename);
+ FILE *fp = fopen(out_filename, "w");
+ if (lst->len == 0) {
+ fprintf(fp, "\n");
+ } else {
+ fprintf(fp, "#EXTM3U\n");
+ fprintf(fp, "#EXT-X-VERSION:3\n");
+ fprintf(fp, "#EXT-X-TARGETDURATION:10\n");
+ fprintf(fp, "#EXT-X-MEDIA-SEQUENCE:%d\n", first_seg);
+ for (int i = 0; i < lst->len; i++) {
+ fprintf(fp, "#EXTINF:%lf\n", lst->times[i]);
+ fprintf(fp, "%s\n", lst->files[i]);
+ }
+ }
+ fclose(fp);
+ upload_file(out_filename, "stream.m3u8");
+}
+
+static void* check_timer(void *vself) {
+ TranscodeTalker *self = vself;
+ while (1) {
+ sleep(15);
+ time_t now;
+ time(&now);
+ pthread_mutex_lock(&self->lock);
+ if (self->lst.len > 0 && now - self->last_updated > 60) {
+ for (int i = 0; i < self->lst.len; i++) {
+ remove_remote(self->lst.files[i]);
+ }
+ HlsList_clear(&self->lst);
+ update_m3u8(&self->lst, -1);
+ }
+ pthread_mutex_unlock(&self->lock);
+ }
+ return NULL;
+}
+
void* TranscodeTalker_main (void *vself) {
+ char remote_prefix[9];
+ char remote_filename[256];
TranscodeTalker *self = vself;
+ int segment_index = 0;
+ tmp_ts_prefix(remote_prefix);
+ pthread_t check_thread;
+ pthread_create(&check_thread, NULL, check_timer, self);
pthread_mutex_lock(&self->lock);
while (wait_for_new_stream(self)) {
AVFormatContext *in_fmt_ctx = avformat_alloc_context();
@@ -99,12 +177,12 @@ void* TranscodeTalker_main (void *vself) {
const AVInputFormat *flv_fmt = av_find_input_format("flv");
if (avformat_open_input(&in_fmt_ctx, NULL, flv_fmt, NULL) < 0) {
fprintf(stderr, "Could not open input file\n");
- abort();
+ continue;
}
if (avformat_find_stream_info(in_fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream info\n");
- abort();
+ continue;
}
int video_stream_index = -1, audio_stream_index = -1;
@@ -117,20 +195,18 @@ void* TranscodeTalker_main (void *vself) {
if (video_stream_index < 0) {
fprintf(stderr, "No video stream found\n");
- abort();
+ continue;
}
if (audio_stream_index < 0) {
fprintf(stderr, "No audio stream found\n");
- abort();
+ continue;
}
AVFormatContext *out_fmt_ctx = NULL;
- int segment_index = 0;
int64_t segment_start_pts = 0;
char out_filename[256];
- snprintf(out_filename, sizeof(out_filename), "segment_%03d.ts", segment_index);
-
+ tmp_local_filename("/tmp/ezlive", out_filename);
int64_t pts_time;
AVPacket pkt;
@@ -155,10 +231,18 @@ void* TranscodeTalker_main (void *vself) {
if (pkt.stream_index == video_stream_index && (pkt.flags & AV_PKT_FLAG_KEY)) {
// close current ts
printf("new ts: %ld\n", pts_time - segment_start_pts);
+ time_t now;
+ time(&now);
+ self->last_updated = now;
finalize_output_file(out_fmt_ctx);
+ ts_filename(remote_prefix, segment_index, remote_filename);
+ upload_file(out_filename, remote_filename);
+ char *deleted = HlsList_push(&self->lst, remote_filename, (pts_time - segment_start_pts) / (double)AV_TIME_BASE);
+ update_m3u8(&self->lst, segment_index);
+ remove_remote(deleted);
+ segment_index++;
// open new ts
- segment_index++;
segment_start_pts = pts_time;
snprintf(out_filename, sizeof(out_filename), "segment_%03d.ts", segment_index);
output_stream = start_new_output_file(in_fmt_ctx, &out_fmt_ctx, out_filename, audio_stream_index, video_stream_index);
@@ -174,7 +258,17 @@ void* TranscodeTalker_main (void *vself) {
av_packet_unref(&pkt);
}
printf("new ts: %ld\n", pts_time - segment_start_pts);
+
finalize_output_file(out_fmt_ctx);
+ time_t now;
+ time(&now);
+ self->last_updated = now;
+ ts_filename(remote_prefix, segment_index, remote_filename);
+ upload_file(out_filename, remote_filename);
+ char *deleted = HlsList_push(&self->lst, remote_filename, (pts_time - segment_start_pts) / (double)AV_TIME_BASE);
+ update_m3u8(&self->lst, segment_index);
+ remove_remote(deleted);
+ segment_index++;
av_free(in_fmt_ctx->pb->buffer);
avio_context_free(&in_fmt_ctx->pb);
@@ -192,6 +286,7 @@ void TranscodeTalker_init(TranscodeTalker *self) {
pthread_cond_init(&self->streaming_cond, NULL);
self->stream = NULL;
self->quit = false;
+ HlsList_init(&self->lst);
}
void TranscodeTalker_new_stream(TranscodeTalker *self, RingBuffer *ringbuf) {
diff --git a/transcode_talker.h b/transcode_talker.h
index 312ae8c..4b0f301 100644
--- a/transcode_talker.h
+++ b/transcode_talker.h
@@ -6,10 +6,18 @@
#include <bits/pthreadtypes.h>
typedef struct {
+ char *files[15];
+ double times[15];
+ int len;
+} HlsList;
+
+typedef struct {
pthread_mutex_t lock;
pthread_cond_t streaming_cond;
RingBuffer *stream;
bool quit;
+ HlsList lst;
+ time_t last_updated;
} TranscodeTalker;
void TranscodeTalker_init(TranscodeTalker *self);