mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-27 12:16:31 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95fcc3c58e | ||
|
|
81500af1b3 | ||
|
|
86a2141361 | ||
|
|
22e5c8627b |
@@ -1,7 +1,7 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
current_version = 5.28
|
current_version = 5.29
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
||||||
serialize =
|
serialize =
|
||||||
{major}.{minor}
|
{major}.{minor}
|
||||||
|
|||||||
@@ -154,9 +154,9 @@ static void *_video_sink_thread(UNUSED void *arg) {
|
|||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
goto close_memsink;
|
goto close_memsink;
|
||||||
}
|
}
|
||||||
// if (frame->key) {
|
if (frame->key) {
|
||||||
// atomic_store(&_g_key_required, false);
|
atomic_store(&_g_key_required, false);
|
||||||
// }
|
}
|
||||||
if (us_queue_put(_g_video_queue, frame, 0) != 0) {
|
if (us_queue_put(_g_video_queue, frame, 0) != 0) {
|
||||||
_IF_NOT_REPORTED({ US_JLOG_PERROR("video", "Video queue is full"); });
|
_IF_NOT_REPORTED({ US_JLOG_PERROR("video", "Video queue is full"); });
|
||||||
us_frame_destroy(frame);
|
us_frame_destroy(frame);
|
||||||
@@ -427,12 +427,7 @@ static struct janus_plugin_result *_plugin_handle_message(
|
|||||||
} else if (!strcmp(request_str, "watch")) {
|
} else if (!strcmp(request_str, "watch")) {
|
||||||
char *sdp;
|
char *sdp;
|
||||||
{
|
{
|
||||||
// atomic_store(&_g_key_required, true);
|
|
||||||
char *const video_sdp = us_rtpv_make_sdp(_g_rtpv);
|
char *const video_sdp = us_rtpv_make_sdp(_g_rtpv);
|
||||||
if (video_sdp == NULL) {
|
|
||||||
PUSH_ERROR(503, "Haven't received SPS/PPS from memsink yet");
|
|
||||||
goto ok_wait;
|
|
||||||
}
|
|
||||||
char *const audio_sdp = (_g_rtpa ? us_rtpa_make_sdp(_g_rtpa) : us_strdup(""));
|
char *const audio_sdp = (_g_rtpa ? us_rtpa_make_sdp(_g_rtpa) : us_strdup(""));
|
||||||
US_ASPRINTF(sdp,
|
US_ASPRINTF(sdp,
|
||||||
"v=0" RN
|
"v=0" RN
|
||||||
@@ -459,6 +454,10 @@ static struct janus_plugin_result *_plugin_handle_message(
|
|||||||
PUSH_STATUS("started", offer_jsep);
|
PUSH_STATUS("started", offer_jsep);
|
||||||
json_decref(offer_jsep);
|
json_decref(offer_jsep);
|
||||||
|
|
||||||
|
} else if (!strcmp(request_str, "key_required")) {
|
||||||
|
US_JLOG_INFO("main", "Got keyframe request from a client");
|
||||||
|
atomic_store(&_g_key_required, true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
PUSH_ERROR(405, "Not implemented");
|
PUSH_ERROR(405, "Not implemented");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,35 +36,15 @@ us_rtpv_s *us_rtpv_init(us_rtp_callback_f callback, bool zero_playout_delay) {
|
|||||||
US_CALLOC(rtpv, 1);
|
US_CALLOC(rtpv, 1);
|
||||||
rtpv->rtp = us_rtp_init(96, true, zero_playout_delay);
|
rtpv->rtp = us_rtp_init(96, true, zero_playout_delay);
|
||||||
rtpv->callback = callback;
|
rtpv->callback = callback;
|
||||||
rtpv->sps = us_frame_init();
|
|
||||||
rtpv->pps = us_frame_init();
|
|
||||||
US_MUTEX_INIT(rtpv->mutex);
|
|
||||||
return rtpv;
|
return rtpv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void us_rtpv_destroy(us_rtpv_s *rtpv) {
|
void us_rtpv_destroy(us_rtpv_s *rtpv) {
|
||||||
US_MUTEX_DESTROY(rtpv->mutex);
|
|
||||||
us_frame_destroy(rtpv->pps);
|
|
||||||
us_frame_destroy(rtpv->sps);
|
|
||||||
us_rtp_destroy(rtpv->rtp);
|
us_rtp_destroy(rtpv->rtp);
|
||||||
free(rtpv);
|
free(rtpv);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *us_rtpv_make_sdp(us_rtpv_s *rtpv) {
|
char *us_rtpv_make_sdp(us_rtpv_s *rtpv) {
|
||||||
US_MUTEX_LOCK(rtpv->mutex);
|
|
||||||
|
|
||||||
if (rtpv->sps->used == 0 || rtpv->pps->used == 0) {
|
|
||||||
US_MUTEX_UNLOCK(rtpv->mutex);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *sps = NULL;
|
|
||||||
char *pps = NULL;
|
|
||||||
us_base64_encode(rtpv->sps->data, rtpv->sps->used, &sps, NULL);
|
|
||||||
us_base64_encode(rtpv->pps->data, rtpv->pps->used, &pps, NULL);
|
|
||||||
|
|
||||||
US_MUTEX_UNLOCK(rtpv->mutex);
|
|
||||||
|
|
||||||
# define PAYLOAD rtpv->rtp->payload
|
# define PAYLOAD rtpv->rtp->payload
|
||||||
// https://tools.ietf.org/html/rfc6184
|
// https://tools.ietf.org/html/rfc6184
|
||||||
// https://github.com/meetecho/janus-gateway/issues/2443
|
// https://github.com/meetecho/janus-gateway/issues/2443
|
||||||
@@ -75,8 +55,6 @@ char *us_rtpv_make_sdp(us_rtpv_s *rtpv) {
|
|||||||
"a=rtpmap:%u H264/90000" RN
|
"a=rtpmap:%u H264/90000" RN
|
||||||
"a=fmtp:%u profile-level-id=42E01F" RN
|
"a=fmtp:%u profile-level-id=42E01F" RN
|
||||||
"a=fmtp:%u packetization-mode=1" RN
|
"a=fmtp:%u packetization-mode=1" RN
|
||||||
"a=fmtp:%u sprop-sps=%s" RN
|
|
||||||
"a=fmtp:%u sprop-pps=%s" RN
|
|
||||||
"a=rtcp-fb:%u nack" RN
|
"a=rtcp-fb:%u nack" RN
|
||||||
"a=rtcp-fb:%u nack pli" RN
|
"a=rtcp-fb:%u nack pli" RN
|
||||||
"a=rtcp-fb:%u goog-remb" RN
|
"a=rtcp-fb:%u goog-remb" RN
|
||||||
@@ -84,17 +62,12 @@ char *us_rtpv_make_sdp(us_rtpv_s *rtpv) {
|
|||||||
"%s" // playout-delay
|
"%s" // playout-delay
|
||||||
"a=sendonly" RN,
|
"a=sendonly" RN,
|
||||||
PAYLOAD, PAYLOAD, PAYLOAD, PAYLOAD,
|
PAYLOAD, PAYLOAD, PAYLOAD, PAYLOAD,
|
||||||
PAYLOAD, sps,
|
|
||||||
PAYLOAD, pps,
|
|
||||||
PAYLOAD, PAYLOAD, PAYLOAD,
|
PAYLOAD, PAYLOAD, PAYLOAD,
|
||||||
rtpv->rtp->ssrc,
|
rtpv->rtp->ssrc,
|
||||||
(rtpv->rtp->zero_playout_delay ? "a=extmap:1 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay" RN : "")
|
(rtpv->rtp->zero_playout_delay ? "a=extmap:1 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay" RN : "")
|
||||||
);
|
);
|
||||||
# undef PAYLOAD
|
|
||||||
|
|
||||||
free(sps);
|
|
||||||
free(pps);
|
|
||||||
return sdp;
|
return sdp;
|
||||||
|
# undef PAYLOAD
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _PRE 3 // Annex B prefix length
|
#define _PRE 3 // Annex B prefix length
|
||||||
@@ -136,22 +109,11 @@ void us_rtpv_wrap(us_rtpv_s *rtpv, const us_frame_s *frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _rtpv_process_nalu(us_rtpv_s *rtpv, const uint8_t *data, size_t size, uint32_t pts, bool marked) {
|
void _rtpv_process_nalu(us_rtpv_s *rtpv, const uint8_t *data, size_t size, uint32_t pts, bool marked) {
|
||||||
|
# define DG rtpv->rtp->datagram
|
||||||
|
|
||||||
const unsigned ref_idc = (data[0] >> 5) & 3;
|
const unsigned ref_idc = (data[0] >> 5) & 3;
|
||||||
const unsigned type = data[0] & 0x1F;
|
const unsigned type = data[0] & 0x1F;
|
||||||
|
|
||||||
us_frame_s *ps = NULL;
|
|
||||||
switch (type) {
|
|
||||||
case 7: ps = rtpv->sps; break;
|
|
||||||
case 8: ps = rtpv->pps; break;
|
|
||||||
}
|
|
||||||
if (ps != NULL) {
|
|
||||||
US_MUTEX_LOCK(rtpv->mutex);
|
|
||||||
us_frame_set_data(ps, data, size);
|
|
||||||
US_MUTEX_UNLOCK(rtpv->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
# define DG rtpv->rtp->datagram
|
|
||||||
|
|
||||||
if (size + US_RTP_HEADER_SIZE <= US_RTP_DATAGRAM_SIZE) {
|
if (size + US_RTP_HEADER_SIZE <= US_RTP_DATAGRAM_SIZE) {
|
||||||
us_rtp_write_header(rtpv->rtp, pts, marked);
|
us_rtp_write_header(rtpv->rtp, pts, marked);
|
||||||
memcpy(DG + US_RTP_HEADER_SIZE, data, size);
|
memcpy(DG + US_RTP_HEADER_SIZE, data, size);
|
||||||
|
|||||||
@@ -31,12 +31,8 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include "uslibs/tools.h"
|
#include "uslibs/tools.h"
|
||||||
#include "uslibs/threading.h"
|
|
||||||
#include "uslibs/frame.h"
|
#include "uslibs/frame.h"
|
||||||
#include "uslibs/base64.h"
|
|
||||||
|
|
||||||
#include "rtp.h"
|
#include "rtp.h"
|
||||||
|
|
||||||
@@ -44,9 +40,6 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
us_rtp_s *rtp;
|
us_rtp_s *rtp;
|
||||||
us_rtp_callback_f callback;
|
us_rtp_callback_f callback;
|
||||||
us_frame_s *sps; // Actually not a frame, just a bytes storage
|
|
||||||
us_frame_s *pps;
|
|
||||||
pthread_mutex_t mutex;
|
|
||||||
} us_rtpv_s;
|
} us_rtpv_s;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
../../../src/libs/base64.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../src/libs/base64.h
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer-dump.
|
.\" Manpage for ustreamer-dump.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER-DUMP 1 "version 5.28" "January 2021"
|
.TH USTREAMER-DUMP 1 "version 5.29" "January 2021"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer-dump \- Dump uStreamer's memory sink to file
|
ustreamer-dump \- Dump uStreamer's memory sink to file
|
||||||
@@ -45,7 +45,7 @@ Limit the number of frames. Default: 0 (infinite).
|
|||||||
.BR \-i ", "\-\-interval\ \fIsec
|
.BR \-i ", "\-\-interval\ \fIsec
|
||||||
Delay between reading frames (float). Default: 0.
|
Delay between reading frames (float). Default: 0.
|
||||||
.TP
|
.TP
|
||||||
.BR \-k ", " \-\-key
|
.BR \-k ", " \-\-key\-required
|
||||||
Request keyframe from the sink. Default: disabled.
|
Request keyframe from the sink. Default: disabled.
|
||||||
|
|
||||||
.SS "Logging options"
|
.SS "Logging options"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer.
|
.\" Manpage for ustreamer.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER 1 "version 5.28" "November 2020"
|
.TH USTREAMER 1 "version 5.29" "November 2020"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
pkgname=ustreamer
|
pkgname=ustreamer
|
||||||
pkgver=5.28
|
pkgver=5.29
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
||||||
url="https://github.com/pikvm/ustreamer"
|
url="https://github.com/pikvm/ustreamer"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=ustreamer
|
PKG_NAME:=ustreamer
|
||||||
PKG_VERSION:=5.28
|
PKG_VERSION:=5.29
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ def _find_sources(suffix: str) -> list[str]:
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
setup(
|
setup(
|
||||||
name="ustreamer",
|
name="ustreamer",
|
||||||
version="5.28",
|
version="5.29",
|
||||||
description="uStreamer tools",
|
description="uStreamer tools",
|
||||||
author="Maxim Devaev",
|
author="Maxim Devaev",
|
||||||
author_email="mdevaev@gmail.com",
|
author_email="mdevaev@gmail.com",
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ enum _OPT_VALUES {
|
|||||||
_O_OUTPUT_JSON = 'j',
|
_O_OUTPUT_JSON = 'j',
|
||||||
_O_COUNT = 'c',
|
_O_COUNT = 'c',
|
||||||
_O_INTERVAL = 'i',
|
_O_INTERVAL = 'i',
|
||||||
_O_KEY = 'k',
|
_O_KEY_REQUIRED = 'k',
|
||||||
|
|
||||||
_O_HELP = 'h',
|
_O_HELP = 'h',
|
||||||
_O_VERSION = 'v',
|
_O_VERSION = 'v',
|
||||||
@@ -68,7 +68,7 @@ static const struct option _LONG_OPTS[] = {
|
|||||||
{"output-json", no_argument, NULL, _O_OUTPUT_JSON},
|
{"output-json", no_argument, NULL, _O_OUTPUT_JSON},
|
||||||
{"count", required_argument, NULL, _O_COUNT},
|
{"count", required_argument, NULL, _O_COUNT},
|
||||||
{"interval", required_argument, NULL, _O_INTERVAL},
|
{"interval", required_argument, NULL, _O_INTERVAL},
|
||||||
{"key", no_argument, NULL, _O_KEY},
|
{"key-required", no_argument, NULL, _O_KEY_REQUIRED},
|
||||||
|
|
||||||
{"log-level", required_argument, NULL, _O_LOG_LEVEL},
|
{"log-level", required_argument, NULL, _O_LOG_LEVEL},
|
||||||
{"perf", no_argument, NULL, _O_PERF},
|
{"perf", no_argument, NULL, _O_PERF},
|
||||||
@@ -154,7 +154,7 @@ int main(int argc, char *argv[]) {
|
|||||||
case _O_OUTPUT_JSON: OPT_SET(output_json, true);
|
case _O_OUTPUT_JSON: OPT_SET(output_json, true);
|
||||||
case _O_COUNT: OPT_NUMBER("--count", count, 0, LLONG_MAX, 0);
|
case _O_COUNT: OPT_NUMBER("--count", count, 0, LLONG_MAX, 0);
|
||||||
case _O_INTERVAL: OPT_LDOUBLE("--interval", interval, 0, 60);
|
case _O_INTERVAL: OPT_LDOUBLE("--interval", interval, 0, 60);
|
||||||
case _O_KEY: OPT_SET(key_required, true);
|
case _O_KEY_REQUIRED: OPT_SET(key_required, true);
|
||||||
|
|
||||||
case _O_LOG_LEVEL: OPT_NUMBER("--log-level", us_g_log_level, US_LOG_LEVEL_INFO, US_LOG_LEVEL_DEBUG, 0);
|
case _O_LOG_LEVEL: OPT_NUMBER("--log-level", us_g_log_level, US_LOG_LEVEL_INFO, US_LOG_LEVEL_DEBUG, 0);
|
||||||
case _O_PERF: OPT_SET(us_g_log_level, US_LOG_LEVEL_PERF);
|
case _O_PERF: OPT_SET(us_g_log_level, US_LOG_LEVEL_PERF);
|
||||||
@@ -332,7 +332,7 @@ static void _help(FILE *fp) {
|
|||||||
SAY(" -j|--output-json ──────── Format output as JSON. Required option --output. Default: disabled.\n");
|
SAY(" -j|--output-json ──────── Format output as JSON. Required option --output. Default: disabled.\n");
|
||||||
SAY(" -c|--count <N> ───────── Limit the number of frames. Default: 0 (infinite).\n");
|
SAY(" -c|--count <N> ───────── Limit the number of frames. Default: 0 (infinite).\n");
|
||||||
SAY(" -i|--interval <sec> ───── Delay between reading frames (float). Default: 0.\n");
|
SAY(" -i|--interval <sec> ───── Delay between reading frames (float). Default: 0.\n");
|
||||||
SAY(" -k|--key ──────────────── Request keyframe from the sink. Default: disabled.\n");
|
SAY(" -k|--key-required ─────── Request keyframe from the sink. Default: disabled.\n");
|
||||||
SAY("Logging options:");
|
SAY("Logging options:");
|
||||||
SAY("════════════════");
|
SAY("════════════════");
|
||||||
SAY(" --log-level <N> ──── Verbosity level of messages from 0 (info) to 3 (debug).");
|
SAY(" --log-level <N> ──── Verbosity level of messages from 0 (info) to 3 (debug).");
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define US_VERSION_MAJOR 5
|
#define US_VERSION_MAJOR 5
|
||||||
#define US_VERSION_MINOR 28
|
#define US_VERSION_MINOR 29
|
||||||
|
|
||||||
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
||||||
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
||||||
|
|||||||
Reference in New Issue
Block a user