0
0
mirror of https://gitlab.xiph.org/xiph/ezstream.git synced 2025-06-30 22:18:27 -04:00

Modernize stream format options

Adds support for WebM/Matroska
Replaces Vorbis and Theora with Ogg
This commit is contained in:
Moritz Grimm 2020-01-24 23:27:02 +01:00
parent 4fe8ea4526
commit b61b78e161
13 changed files with 138 additions and 62 deletions

View File

@ -343,13 +343,15 @@ Default:
.Pq Mandatory. .Pq Mandatory.
The stream format. The stream format.
.Pp .Pp
.Bl -tag -width VORBIS -compact .Bl -tag -width Matroska -compact
.It Ar Vorbis .It Ar Ogg
Ogg Vorbis audio format Ogg media format
.It Ar MP3 .It Ar MP3
MP3 audio format MP3 audio format
.It Ar Theora .It Ar WebM
Ogg Theora video format WebM media format
.It Ar Matroska
Matroska media format
.El .El
.It Sy \&<encoder\ /\&> .It Sy \&<encoder\ /\&>
Use the encoder configuration with the provided symbolic name Use the encoder configuration with the provided symbolic name

View File

@ -21,7 +21,7 @@
<streams> <streams>
<stream> <stream>
<mountpoint>/stream.ogg</mountpoint> <mountpoint>/stream.ogg</mountpoint>
<format>Vorbis</format> <format>Ogg</format>
<encoder>OggEnc-Q1.5</encoder> <encoder>OggEnc-Q1.5</encoder>
</stream> </stream>
</streams> </streams>
@ -56,7 +56,7 @@
<encoders> <encoders>
<encoder> <encoder>
<name>OggEnc-Q1.5</name> <name>OggEnc-Q1.5</name>
<format>Vorbis</format> <format>Ogg</format>
<program>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t @M@ -</program> <program>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t @M@ -</program>
</encoder> </encoder>

View File

@ -100,8 +100,8 @@
--> -->
<public>No</public> <public>No</public>
<!-- Stream format: Vorbis, MP3, Theora --> <!-- Stream format: Ogg, MP3, WebM, Matroska -->
<format>Vorbis</format> <format>Ogg</format>
<!-- Encoder name (defined below) to use for (re)encoding --> <!-- Encoder name (defined below) to use for (re)encoding -->
<encoder>OggEnc-Q1.5</encoder> <encoder>OggEnc-Q1.5</encoder>
@ -198,7 +198,7 @@
<!-- Encoder name --> <!-- Encoder name -->
<name>OggEnc-Q1.5</name> <name>OggEnc-Q1.5</name>
<!-- Output stream format --> <!-- Output stream format -->
<format>Vorbis</format> <format>Ogg</format>
<!-- Program and options --> <!-- Program and options -->
<program>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 1 -q 1.5 -t @M@ -</program> <program>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 1 -q 1.5 -t @M@ -</program>
</encoder> </encoder>

View File

@ -16,7 +16,7 @@
<streams> <streams>
<stream> <stream>
<mountpoint>/stream.ogg</mountpoint> <mountpoint>/stream.ogg</mountpoint>
<format>Vorbis</format> <format>Ogg</format>
</stream> </stream>
</streams> </streams>

View File

@ -3,7 +3,7 @@
<!-- <!--
EXAMPLE: A valid configuration that contains the absolute minimum EXAMPLE: A valid configuration that contains the absolute minimum
This configuration streams Ogg Vorbis files as-is. This configuration streams Ogg files as-is.
--> -->
<ezstream> <ezstream>
@ -18,7 +18,7 @@
<streams> <streams>
<stream> <stream>
<mountpoint>/stream.ogg</mountpoint> <mountpoint>/stream.ogg</mountpoint>
<format>Vorbis</format> <format>Ogg</format>
</stream> </stream>
</streams> </streams>

View File

@ -18,7 +18,7 @@
<streams> <streams>
<stream> <stream>
<mountpoint>/stream.ogg</mountpoint> <mountpoint>/stream.ogg</mountpoint>
<format>Vorbis</format> <format>Ogg</format>
</stream> </stream>
</streams> </streams>

View File

@ -16,7 +16,7 @@
<streams> <streams>
<stream> <stream>
<mountpoint>/video.ogg</mountpoint> <mountpoint>/video.ogg</mountpoint>
<format>Theora</format> <format>Ogg</format>
<!-- No encoder configured (see below). --> <!-- No encoder configured (see below). -->
</stream> </stream>
</streams> </streams>

View File

@ -169,12 +169,14 @@ cfg_stream_destroy(struct cfg_stream **s_p)
int int
cfg_stream_str2fmt(const char *str, enum cfg_stream_format *fmt_p) cfg_stream_str2fmt(const char *str, enum cfg_stream_format *fmt_p)
{ {
if (0 == strcasecmp(str, CFG_SFMT_VORBIS)) { if (0 == strcasecmp(str, CFG_SFMT_OGG)) {
*fmt_p = CFG_STREAM_VORBIS; *fmt_p = CFG_STREAM_OGG;
} else if (0 == strcasecmp(str, CFG_SFMT_MP3)) { } else if (0 == strcasecmp(str, CFG_SFMT_MP3)) {
*fmt_p = CFG_STREAM_MP3; *fmt_p = CFG_STREAM_MP3;
} else if (0 == strcasecmp(str, CFG_SFMT_THEORA)) { } else if (0 == strcasecmp(str, CFG_SFMT_WEBM)) {
*fmt_p = CFG_STREAM_THEORA; *fmt_p = CFG_STREAM_WEBM;
} else if (0 == strcasecmp(str, CFG_SFMT_MATROSKA)) {
*fmt_p = CFG_STREAM_MATROSKA;
} else } else
return (-1); return (-1);
return (0); return (0);
@ -184,12 +186,14 @@ const char *
cfg_stream_fmt2str(enum cfg_stream_format fmt) cfg_stream_fmt2str(enum cfg_stream_format fmt)
{ {
switch (fmt) { switch (fmt) {
case CFG_STREAM_VORBIS: case CFG_STREAM_OGG:
return (CFG_SFMT_VORBIS); return (CFG_SFMT_OGG);
case CFG_STREAM_MP3: case CFG_STREAM_MP3:
return (CFG_SFMT_MP3); return (CFG_SFMT_MP3);
case CFG_STREAM_THEORA: case CFG_STREAM_WEBM:
return (CFG_SFMT_THEORA); return (CFG_SFMT_WEBM);
case CFG_STREAM_MATROSKA:
return (CFG_SFMT_MATROSKA);
default: default:
return (NULL); return (NULL);
} }

View File

@ -17,17 +17,19 @@
#ifndef __CFG_STREAM_H__ #ifndef __CFG_STREAM_H__
#define __CFG_STREAM_H__ #define __CFG_STREAM_H__
#define CFG_SFMT_VORBIS "VORBIS" #define CFG_SFMT_OGG "Ogg"
#define CFG_SFMT_MP3 "MP3" #define CFG_SFMT_MP3 "MP3"
#define CFG_SFMT_THEORA "THEORA" #define CFG_SFMT_WEBM "WebM"
#define CFG_SFMT_MATROSKA "Matroska"
enum cfg_stream_format { enum cfg_stream_format {
CFG_STREAM_INVALID = 0, CFG_STREAM_INVALID = 0,
CFG_STREAM_VORBIS, CFG_STREAM_OGG,
CFG_STREAM_MP3, CFG_STREAM_MP3,
CFG_STREAM_THEORA, CFG_STREAM_WEBM,
CFG_STREAM_MIN = CFG_STREAM_VORBIS, CFG_STREAM_MATROSKA,
CFG_STREAM_MAX = CFG_STREAM_THEORA, CFG_STREAM_MIN = CFG_STREAM_OGG,
CFG_STREAM_MAX = CFG_STREAM_MATROSKA,
}; };
typedef struct cfg_stream * cfg_stream_t; typedef struct cfg_stream * cfg_stream_t;

View File

@ -206,9 +206,15 @@ _parse_ezconfig0(EZCONFIG *ez)
if (ez->password) if (ez->password)
ENTITY_SET(srv, srv_list, cfg_server_set_password, ENTITY_SET(srv, srv_list, cfg_server_set_password,
"<sourcepassword>", ez->password); "<sourcepassword>", ez->password);
if (ez->format) if (ez->format) {
ENTITY_SET(str, str_list, cfg_stream_set_format, if (0 == strcasecmp(ez->format, "vorbis") ||
"<format>", ez->format); 0 == strcasecmp(ez->format, "theora"))
ENTITY_SET(str, str_list, cfg_stream_set_format,
"<format>", "Ogg");
else
ENTITY_SET(str, str_list, cfg_stream_set_format,
"<format>", ez->format);
}
if (ez->fileName) { if (ez->fileName) {
if (0 == strcasecmp(ez->fileName, "stdin")) if (0 == strcasecmp(ez->fileName, "stdin"))
ENTITY_SET(in, in_list, cfg_intake_set_type, ENTITY_SET(in, in_list, cfg_intake_set_type,
@ -281,9 +287,15 @@ _parse_ezconfig0(EZCONFIG *ez)
"<svrinfoquality>", ez->serverQuality); "<svrinfoquality>", ez->serverQuality);
ENTITY_SET(str, str_list, cfg_stream_set_public, ENTITY_SET(str, str_list, cfg_stream_set_public,
"<svrinfopublic>", ez->serverPublic ? "yes" : "no"); "<svrinfopublic>", ez->serverPublic ? "yes" : "no");
if (ez->reencode) if (ez->reencode) {
ENTITY_SET(str, str_list, cfg_stream_set_encoder, "<reencode>", if (0 == strcasecmp(ez->format, "vorbis") ||
ez->format); 0 == strcasecmp(ez->format, "theora"))
ENTITY_SET(str, str_list, cfg_stream_set_encoder,
"<reencode>", "Ogg");
else
ENTITY_SET(str, str_list, cfg_stream_set_encoder,
"<reencode>", ez->format);
}
for (i = 0; i < MAX_FORMAT_ENCDEC; i++) { for (i = 0; i < MAX_FORMAT_ENCDEC; i++) {
FORMAT_ENCDEC *ed = ez->encoderDecoders[i]; FORMAT_ENCDEC *ed = ez->encoderDecoders[i];
@ -298,10 +310,26 @@ _parse_ezconfig0(EZCONFIG *ez)
ENTITY_SET(enc, enc_list, cfg_encoder_set_program, ENTITY_SET(enc, enc_list, cfg_encoder_set_program,
"<encode>", ed->encoder); "<encode>", ed->encoder);
if (ed->format) { if (ed->format) {
ENTITY_SET(enc, enc_list, cfg_encoder_set_name, if (0 == strcasecmp(ed->format, "vorbis") ||
"<format> (encoder)", ed->format); 0 == strcasecmp(ed->format, "theora")) {
ENTITY_SET(enc, enc_list, cfg_encoder_set_format_str, ENTITY_SET(enc, enc_list,
"<format> (encoder)", ed->format); cfg_encoder_set_name,
"<format> (encoder)",
"Ogg");
ENTITY_SET(enc, enc_list,
cfg_encoder_set_format_str,
"<format> (encoder)",
"Ogg");
} else {
ENTITY_SET(enc, enc_list,
cfg_encoder_set_name,
"<format> (encoder)",
ed->format);
ENTITY_SET(enc, enc_list,
cfg_encoder_set_format_str,
"<format> (encoder)",
ed->format);
}
} }
if (0 > cfg_encoder_validate(enc, &err_str)) { if (0 > cfg_encoder_validate(enc, &err_str)) {
log_warning("%s: %s: %s", v0_cfgfile, log_warning("%s: %s: %s", v0_cfgfile,
@ -313,16 +341,33 @@ _parse_ezconfig0(EZCONFIG *ez)
if (ed->decoder) { if (ed->decoder) {
cfg_decoder_t dec = NULL; cfg_decoder_t dec = NULL;
if (ed->format) if (ed->format) {
dec = cfg_decoder_list_find(dec_list, ed->format); if (0 == strcasecmp(ed->format, "vorbis") ||
0 == strcasecmp(ed->format, "theora"))
dec = cfg_decoder_list_find(dec_list,
"Ogg");
else
dec = cfg_decoder_list_find(dec_list,
ed->format);
}
if (NULL == dec) if (NULL == dec)
dec = cfg_decoder_list_get(dec_list, CFG_DEFAULT); dec = cfg_decoder_list_get(dec_list, CFG_DEFAULT);
ENTITY_SET(dec, dec_list, cfg_decoder_set_program, ENTITY_SET(dec, dec_list, cfg_decoder_set_program,
"<decode>", ed->decoder); "<decode>", ed->decoder);
if (ed->format) if (ed->format) {
ENTITY_SET(dec, dec_list, cfg_decoder_set_name, if (0 == strcasecmp(ed->format, "vorbis") ||
"<format> (decoder)", ed->format); 0 == strcasecmp(ed->format, "theora"))
ENTITY_SET(dec, dec_list,
cfg_decoder_set_name,
"<format> (decoder)",
"Ogg");
else
ENTITY_SET(dec, dec_list,
cfg_decoder_set_name,
"<format> (decoder)",
ed->format);
}
if (ed->match) if (ed->match)
ENTITY_SET(dec, dec_list, cfg_decoder_add_match, ENTITY_SET(dec, dec_list, cfg_decoder_add_match,
"<match>", ed->match); "<match>", ed->match);

View File

@ -216,8 +216,7 @@ _stream_cfg_stream(struct stream *s, cfg_stream_t cfg_stream)
return (-1); return (-1);
} }
switch (cfg_stream_get_format(cfg_stream)) { switch (cfg_stream_get_format(cfg_stream)) {
case CFG_STREAM_VORBIS: case CFG_STREAM_OGG:
case CFG_STREAM_THEORA:
if (SHOUTERR_SUCCESS != if (SHOUTERR_SUCCESS !=
shout_set_format(s->shout, SHOUT_FORMAT_OGG)) { shout_set_format(s->shout, SHOUT_FORMAT_OGG)) {
log_error("stream: %s: format_ogg: %s", log_error("stream: %s: format_ogg: %s",
@ -233,6 +232,24 @@ _stream_cfg_stream(struct stream *s, cfg_stream_t cfg_stream)
return (-1); return (-1);
} }
break; break;
case CFG_STREAM_WEBM:
if (SHOUTERR_SUCCESS !=
shout_set_format(s->shout, SHOUT_FORMAT_WEBM)) {
log_error("stream: %s: format_mp3: %s",
s->name, shout_get_error(s->shout));
return (-1);
}
break;
#ifdef SHOUT_FORMAT_MATROSKA
case CFG_STREAM_MATROSKA:
if (SHOUTERR_SUCCESS !=
shout_set_format(s->shout, SHOUT_FORMAT_MATROSKA)) {
log_error("stream: %s: format_mp3: %s",
s->name, shout_get_error(s->shout));
return (-1);
}
break;
#endif /* SHOUT_FORMAT_MATROSKA */
default: default:
log_error("stream: %s: format: unsupported: %s", log_error("stream: %s: format: unsupported: %s",
s->name, cfg_stream_get_format_str(cfg_stream)); s->name, cfg_stream_get_format_str(cfg_stream));

View File

@ -77,12 +77,14 @@ START_TEST(test_encoder_set_format_str)
ck_assert_str_eq(errstr, "unsupported stream format"); ck_assert_str_eq(errstr, "unsupported stream format");
ck_assert_int_eq(cfg_encoder_set_format_str(enc, encoders, ck_assert_int_eq(cfg_encoder_set_format_str(enc, encoders,
CFG_SFMT_VORBIS, NULL), 0); CFG_SFMT_OGG, NULL), 0);
ck_assert_int_eq(cfg_encoder_set_format_str(enc, encoders, ck_assert_int_eq(cfg_encoder_set_format_str(enc, encoders,
CFG_SFMT_MP3, NULL), 0); CFG_SFMT_MP3, NULL), 0);
ck_assert_int_eq(cfg_encoder_set_format_str(enc, encoders, ck_assert_int_eq(cfg_encoder_set_format_str(enc, encoders,
CFG_SFMT_THEORA, NULL), 0); CFG_SFMT_MP3, NULL), 0);
ck_assert_uint_eq(cfg_encoder_get_format(enc), CFG_STREAM_THEORA); ck_assert_int_eq(cfg_encoder_set_format_str(enc, encoders,
CFG_SFMT_MATROSKA, NULL), 0);
ck_assert_uint_eq(cfg_encoder_get_format(enc), CFG_STREAM_MATROSKA);
} }
END_TEST END_TEST
@ -101,7 +103,7 @@ START_TEST(test_encoder_validate)
ck_assert_int_ne(cfg_encoder_validate(enc, &errstr), 0); ck_assert_int_ne(cfg_encoder_validate(enc, &errstr), 0);
ck_assert_str_eq(errstr, "format not set"); ck_assert_str_eq(errstr, "format not set");
ck_assert_int_eq(cfg_encoder_set_format(enc, CFG_STREAM_VORBIS), 0); ck_assert_int_eq(cfg_encoder_set_format(enc, CFG_STREAM_OGG), 0);
ck_assert_int_ne(cfg_encoder_validate(enc, &errstr), 0); ck_assert_int_ne(cfg_encoder_validate(enc, &errstr), 0);
ck_assert_str_eq(errstr, "program not set"); ck_assert_str_eq(errstr, "program not set");

View File

@ -47,24 +47,28 @@ START_TEST(test_stream_str2fmt)
{ {
enum cfg_stream_format fmt; enum cfg_stream_format fmt;
ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_VORBIS, &fmt), 0); ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_OGG, &fmt), 0);
ck_assert_int_eq(fmt, CFG_STREAM_VORBIS); ck_assert_int_eq(fmt, CFG_STREAM_OGG);
ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_MP3, &fmt), 0); ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_MP3, &fmt), 0);
ck_assert_int_eq(fmt, CFG_STREAM_MP3); ck_assert_int_eq(fmt, CFG_STREAM_MP3);
ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_THEORA, &fmt), 0); ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_WEBM, &fmt), 0);
ck_assert_int_eq(fmt, CFG_STREAM_THEORA); ck_assert_int_eq(fmt, CFG_STREAM_WEBM);
ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_MATROSKA, &fmt), 0);
ck_assert_int_eq(fmt, CFG_STREAM_MATROSKA);
ck_assert_int_eq(cfg_stream_str2fmt("<something else>", &fmt), -1); ck_assert_int_eq(cfg_stream_str2fmt("<something else>", &fmt), -1);
} }
END_TEST END_TEST
START_TEST(test_stream_fmt2str) START_TEST(test_stream_fmt2str)
{ {
ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_VORBIS), ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_OGG),
CFG_SFMT_VORBIS); CFG_SFMT_OGG);
ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_MP3), ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_MP3),
CFG_SFMT_MP3); CFG_SFMT_MP3);
ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_THEORA), ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_WEBM),
CFG_SFMT_THEORA); CFG_SFMT_WEBM);
ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_MATROSKA),
CFG_SFMT_MATROSKA);
ck_assert_ptr_eq(cfg_stream_fmt2str(CFG_STREAM_INVALID), NULL); ck_assert_ptr_eq(cfg_stream_fmt2str(CFG_STREAM_INVALID), NULL);
} }
END_TEST END_TEST
@ -116,11 +120,11 @@ START_TEST(test_stream_format)
"<something else>", &errstr2), -1); "<something else>", &errstr2), -1);
ck_assert_str_eq(errstr2, "unsupported stream format"); ck_assert_str_eq(errstr2, "unsupported stream format");
ck_assert_int_eq(cfg_stream_set_format(str, streams, CFG_SFMT_VORBIS, ck_assert_int_eq(cfg_stream_set_format(str, streams, CFG_SFMT_OGG,
NULL), 0); NULL), 0);
ck_assert_int_eq(cfg_stream_get_format(str), CFG_STREAM_VORBIS); ck_assert_int_eq(cfg_stream_get_format(str), CFG_STREAM_OGG);
ck_assert_str_eq(cfg_stream_get_format_str(str), ck_assert_str_eq(cfg_stream_get_format_str(str),
cfg_stream_fmt2str(CFG_STREAM_VORBIS)); cfg_stream_fmt2str(CFG_STREAM_OGG));
} }
END_TEST END_TEST
@ -197,7 +201,7 @@ START_TEST(test_stream_validate)
ck_assert_int_ne(cfg_stream_validate(str, &errstr), 0); ck_assert_int_ne(cfg_stream_validate(str, &errstr), 0);
ck_assert_ptr_ne(errstr, NULL); ck_assert_ptr_ne(errstr, NULL);
ck_assert_str_eq(errstr, "format missing or unsupported"); ck_assert_str_eq(errstr, "format missing or unsupported");
ck_assert_int_eq(cfg_stream_set_format(str, streams, CFG_SFMT_VORBIS, ck_assert_int_eq(cfg_stream_set_format(str, streams, CFG_SFMT_OGG,
NULL), 0); NULL), 0);
ck_assert_int_eq(cfg_stream_validate(str, NULL), 0); ck_assert_int_eq(cfg_stream_validate(str, NULL), 0);