[FFmpeg-devel] [PATCH 3/4] ffserver: Implement ffserver and add Makefile

2018-04-16 Thread Stephan Holljes
---
 Makefile   |  15 ++
 ffserver.c | 477 +
 2 files changed, 492 insertions(+)
 create mode 100644 Makefile
 create mode 100644 ffserver.c

diff --git a/Makefile b/Makefile
new file mode 100644
index 000..b077039
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+all: ffserver
+LAV_FLAGS = $(shell pkg-config --libs --cflags libavformat libavcodec 
libavutil)
+# LAV_FLAGS = -L/usr/local/lib -lavcodec -lavformat -lavutil
+
+ffserver: segment.o publisher.o ffserver.c
+   cc -g -Wall $(LAV_FLAGS)  -lpthread -o ffserver segment.o publisher.o 
ffserver.c
+
+segment.o: segment.c segment.h
+   cc -g -Wall $(LAV_FLAGS) -lpthread -c segment.c
+
+publisher.o: publisher.c publisher.h
+   cc -g -Wall $(LAV_FLAGS) -lpthread -c publisher.c
+
+clean:
+   rm *.o ffserver
diff --git a/ffserver.c b/ffserver.c
new file mode 100644
index 000..b0ff00e
--- /dev/null
+++ b/ffserver.c
@@ -0,0 +1,477 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * multimedia server based on the FFmpeg libraries
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "segment.h"
+#include "publisher.h"
+
+#define BUFFER_SECS 30
+#define LISTEN_TIMEOUT_MSEC 1000
+
+struct ReadInfo {
+struct PublisherContext *pub;
+AVFormatContext *ifmt_ctx;
+char *in_filename;
+};
+
+struct WriteInfo {
+struct PublisherContext *pub;
+int thread_id;
+};
+
+struct AcceptInfo {
+struct PublisherContext *pub;
+AVFormatContext *ifmt_ctx;
+const char *out_uri;
+};
+
+
+void *read_thread(void *arg)
+{
+struct ReadInfo *info = (struct ReadInfo*) arg;
+AVFormatContext *ifmt_ctx = info->ifmt_ctx;
+int ret, i;
+int video_idx = -1;
+int id = 0;
+int64_t pts, now, start;
+int64_t *ts;
+struct Segment *seg = NULL;
+AVPacket pkt;
+AVStream *in_stream;
+AVRational tb;
+tb.num = 1;
+tb.den = AV_TIME_BASE;
+AVStream *stream;
+AVCodecParameters *params;
+enum AVMediaType type;
+
+if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {
+av_log(ifmt_ctx, AV_LOG_ERROR, "Could not get input stream info.\n");
+goto end;
+}
+
+av_log(ifmt_ctx, AV_LOG_INFO, "Finding video stream.\n");
+for (i = 0; i < ifmt_ctx->nb_streams; i++) {
+av_log(ifmt_ctx, AV_LOG_DEBUG, "Checking stream %d\n", i);
+stream = ifmt_ctx->streams[i];
+params = stream->codecpar;
+type = params->codec_type;
+if (type == AVMEDIA_TYPE_VIDEO) {
+video_idx = i;
+break;
+}
+}
+if (video_idx == -1) {
+av_log(ifmt_ctx, AV_LOG_ERROR, "No video stream found.\n");
+goto end;
+}
+
+
+// All information needed to start segmenting the file is gathered now.
+// start BUFFER_SECS seconds "in the past" to "catch up" to real-time. Has 
no effect on streamed sources.
+start = av_gettime_relative() - BUFFER_SECS * AV_TIME_BASE;
+
+// segmenting main-loop
+
+for (;;) {
+ret = av_read_frame(ifmt_ctx, &pkt);
+if (ret < 0)
+break;
+
+in_stream = ifmt_ctx->streams[pkt.stream_index];
+if (pkt.pts == AV_NOPTS_VALUE) {
+pkt.pts = 0;
+}
+if (pkt.dts == AV_NOPTS_VALUE) {
+pkt.dts = 0;
+}
+
+// current pts
+pts = av_rescale_q(pkt.pts, in_stream->time_base, tb);
+
+// current stream "uptime"
+now = av_gettime_relative() - start;
+
+// simulate real-time reading
+while (pts > now) {
+usleep(1000);
+now = av_gettime_relative() - start;
+}
+
+// keyframe or first Segment
+if ((pkt.flags & AV_PKT_FLAG_KEY && pkt.stream_index == video_idx) || 
!seg) {
+if (seg) {
+segment_close(seg);
+publisher_push_segment(info->pub, seg);
+av_log(NULL, AV_LOG_DEBUG, "New segment pushed.\n");
+publish(info->pub);
+   av_log(NULL, AV_LOG_DEBUG, "Published new 
segment.\n");
+}
+  

[FFmpeg-devel] [PATCH 3/4] ffserver: Implement ffserver and add Makefile

2018-04-12 Thread Stephan Holljes
---
 Makefile   |  15 ++
 ffserver.c | 451 +
 2 files changed, 466 insertions(+)
 create mode 100644 Makefile
 create mode 100644 ffserver.c

diff --git a/Makefile b/Makefile
new file mode 100644
index 000..a57393a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+all: ffserver
+LAV_FLAGS = $(shell pkg-config --libs --cflags libavformat libavcodec 
libavutil)
+# LAV_FLAGS = -L/usr/local/lib -lavcodec -lavformat -lavutil
+
+ffserver: segment.o publisher.o ffserver.c
+   cc -g -Wall $(LAV_FLAGS)  -lpthread -o ffserver segment.o publisher.o 
ffserver.c
+
+segment.o: segment.c segment.h
+   cc -g -Wall $(LAV_FLAGS) -lpthread -c segment.c
+
+publisher.o: publisher.c publisher.h
+   cc -g -Wall $(LAV_FLAGS) -lpthread -c publisher.c
+
+clean:
+   rm *.o server
diff --git a/ffserver.c b/ffserver.c
new file mode 100644
index 000..ecdcc64
--- /dev/null
+++ b/ffserver.c
@@ -0,0 +1,451 @@
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "segment.h"
+#include "publisher.h"
+
+#define  BUFFER_SECS 30
+#define LISTEN_TIMEOUT_MSEC 1000
+
+struct ReadInfo {
+struct PublisherContext *pub;
+AVFormatContext *ifmt_ctx;
+char *in_filename;
+};
+
+struct WriteInfo {
+struct PublisherContext *pub;
+int thread_id;
+};
+
+struct AcceptInfo {
+struct PublisherContext *pub;
+AVFormatContext *ifmt_ctx;
+const char *out_uri;
+};
+
+
+void *read_thread(void *arg)
+{
+struct ReadInfo *info = (struct ReadInfo*) arg;
+AVFormatContext *ifmt_ctx = info->ifmt_ctx;
+int ret, i;
+int video_idx = -1;
+int id = 0;
+int64_t pts, now, start;
+struct Segment *seg = NULL;
+AVPacket pkt;
+AVStream *in_stream;
+AVRational tb;
+tb.num = 1;
+tb.den = AV_TIME_BASE;
+AVStream *stream;
+AVCodecContext *avctx;
+AVCodecParameters *params;
+enum AVMediaType type;
+
+if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {
+av_log(NULL, AV_LOG_ERROR, "Could not get input stream info.\n");
+goto end;
+}
+
+av_log(NULL, AV_LOG_INFO, "Finding video stream.\n");
+for (i = 0; i < ifmt_ctx->nb_streams; i++) {
+av_log(NULL, AV_LOG_DEBUG, "Checking stream %d\n", i);
+stream = ifmt_ctx->streams[i];
+avctx = avcodec_alloc_context3(NULL);
+if (!avctx) {
+av_log(NULL, AV_LOG_ERROR, "Could not allocate AVCodecContext.\n");
+goto end;
+}
+if ((ret = avcodec_parameters_to_context(avctx, stream->codecpar)) < 
0) {
+av_log(NULL, AV_LOG_ERROR, "Could not copy codec parameters.\n");
+goto end;
+}
+params = stream->codecpar;
+type = params->codec_type;
+if (type == AVMEDIA_TYPE_VIDEO) {
+video_idx = i;
+break;
+}
+}
+if (video_idx == -1) {
+av_log(NULL, AV_LOG_ERROR, "No video stream found.\n");
+goto end;
+}
+
+
+// All information needed to start segmenting the file is gathered now.
+// start BUFFER_SECS seconds "in the past" to "catch up" to real-time. Has 
no effect on streamed sources.
+start = av_gettime_relative() - BUFFER_SECS * AV_TIME_BASE;
+
+// segmenting main-loop
+
+for (;;) {
+ret = av_read_frame(ifmt_ctx, &pkt);
+if (ret < 0)
+break;
+
+in_stream = ifmt_ctx->streams[pkt.stream_index];
+if (pkt.pts == AV_NOPTS_VALUE) {
+pkt.pts = 0;
+}
+if (pkt.dts == AV_NOPTS_VALUE) {
+pkt.dts = 0;
+}
+
+// current pts
+pts = av_rescale_q(pkt.pts, in_stream->time_base, tb);
+
+// current stream "uptime"
+now = av_gettime_relative() - start;
+
+// simulate real-time reading
+while (pts > now) {
+usleep(1000);
+now = av_gettime_relative() - start;
+}
+
+// keyframe or first Segment
+if ((pkt.flags & AV_PKT_FLAG_KEY && pkt.stream_index == video_idx) || 
!seg) {
+if (seg) {
+segment_close(seg);
+
+publisher_push_segment(info->pub, seg);
+av_log(NULL, AV_LOG_DEBUG, "New segment pushed.\n");
+publish(info->pub);
+   av_log(NULL, AV_LOG_DEBUG, "Published new 
segment.\n");
+}
+segment_init(&seg, ifmt_ctx);
+seg->id = id++;
+av_log(NULL, AV_LOG_DEBUG, "Starting new segment, id: %d\n", 
seg->id);
+}
+
+segment_ts_append(seg, pkt.dts, pkt.pts);
+ret = av_write_frame(seg->fmt_ctx, &pkt);
+av_packet_unref(&pkt);
+if (ret < 0) {
+av_log(NULL,AV_LOG_ERROR, "av_write_frame() failed.\n");
+goto end;
+}
+}
+
+if (ret