aboutsummaryrefslogtreecommitdiff
path: root/transcode_talker.c
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-09-13 16:44:13 +0800
committerMistivia <i@mistivia.com>2025-09-13 16:44:13 +0800
commitf3eeea1d7092f3ca98836035bf75b941d14c2067 (patch)
tree694dcda14f42c48959340e086ae94b021f9d18f8 /transcode_talker.c
parent7540ded75ee07b026950486172aca08cd0686a4e (diff)
write m3u8
Diffstat (limited to 'transcode_talker.c')
-rw-r--r--transcode_talker.c113
1 files changed, 104 insertions, 9 deletions
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) {