From: Hypfer Date: Thu, 25 Aug 2016 19:29:53 +0000 (+0200) Subject: Re-add Audioes muxer X-Git-Tag: v4.2.1~282 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=81056b1a9e4b5a2fc00906c8d7db0251254dec21;p=thirdparty%2Ftvheadend.git Re-add Audioes muxer --- diff --git a/src/muxer.c b/src/muxer.c index c6bb6ef2e..c68e82b43 100644 --- a/src/muxer.c +++ b/src/muxer.c @@ -24,6 +24,7 @@ #include "muxer.h" #include "muxer/muxer_mkv.h" #include "muxer/muxer_pass.h" +#include "muxer/muxer_audioes.h" #if CONFIG_LIBAV #include "muxer/muxer_libav.h" #endif @@ -48,6 +49,7 @@ static struct strtab container_audio_mime[] = { { "audio/mp4", MC_AVMP4 }, { "application/octet-stream", MC_PASS }, { "application/octet-stream", MC_RAW }, + { "audio/mpeg", MC_AUDIOES }, }; @@ -82,6 +84,7 @@ static struct strtab container_name[] = { { "avmatroska", MC_AVMATROSKA }, { "avwebm", MC_AVWEBM }, { "avmp4", MC_AVMP4 }, + { "audioes", MC_AUDIOES }, }; @@ -99,6 +102,7 @@ static struct strtab container_audio_file_suffix[] = { { "mka", MC_AVMATROSKA }, { "webm", MC_AVWEBM }, { "mp4", MC_AVMP4 }, + { "mp2", MC_AUDIOES }, /* Or maybe ac3 or adts */ }; @@ -116,6 +120,7 @@ static struct strtab container_video_file_suffix[] = { { "mkv", MC_AVMATROSKA }, { "webm", MC_AVWEBM }, { "mp4", MC_AVMP4 }, + { NULL, MC_AUDIOES }, }; @@ -255,6 +260,9 @@ muxer_create(const muxer_config_t *m_cfg) if(!m) m = mkv_muxer_create(m_cfg); + if(!m) + m = audioes_muxer_create(m_cfg); + #if CONFIG_LIBAV if(!m) m = lav_muxer_create(m_cfg); diff --git a/src/muxer.h b/src/muxer.h index d0bedff9f..b78839539 100644 --- a/src/muxer.h +++ b/src/muxer.h @@ -34,6 +34,7 @@ typedef enum { MC_AVMATROSKA = 7, MC_AVWEBM = 8, MC_AVMP4 = 9, + MC_AUDIOES = 10 } muxer_container_type_t; typedef enum { diff --git a/src/muxer/muxer_audioes.c b/src/muxer/muxer_audioes.c new file mode 100644 index 000000000..ebc905495 --- /dev/null +++ b/src/muxer/muxer_audioes.c @@ -0,0 +1,265 @@ +/* + * "muxer" to write mpeg audio elementary streams + * Copyright (C) 2013 Dave Chapman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "tvheadend.h" +#include "streaming.h" +#include "epg.h" +#include "channels.h" +#include "muxer_audioes.h" + +typedef struct audioes_muxer { + muxer_t; + + int error; + + /* Info about the service */ + int am_index; + + /* File descriptor stuff */ + int am_fd; + int am_seekable; + int am_error; + + /* Filename is also used for logging */ + char *am_filename; +} audioes_muxer_t; + + +/** + * Figure out the mimetype + */ +static const char* +audioes_muxer_mime(muxer_t* m, const struct streaming_start *ss) +{ + int i; + int has_audio; + const streaming_start_component_t *ssc; + + has_audio = 0; + + for(i=0; i < ss->ss_num_components; i++) { + ssc = &ss->ss_components[i]; + + if(ssc->ssc_disabled) + continue; + + has_audio |= SCT_ISAUDIO(ssc->ssc_type); + } + + if(has_audio) + return muxer_container_type2mime(MC_AUDIOES, 0); + else + return muxer_container_type2mime(MC_UNKNOWN, 0); +} + + +/** + * Init the builtin mkv muxer with streams + */ +static int +audioes_muxer_init(muxer_t* m, struct streaming_start *ss, const char *name) +{ + audioes_muxer_t *am = (audioes_muxer_t*)m; + const streaming_start_component_t *ssc; + int i; + + am->am_index = -1; + + for(i = 0; i < ss->ss_num_components;i++) { + ssc = &ss->ss_components[i]; + + if ((!ssc->ssc_disabled) && (SCT_ISAUDIO(ssc->ssc_type))) { + am->am_index = ssc->ssc_index; + break; + } + } + + return 0; +} + + +static int +audioes_muxer_reconfigure(muxer_t* m, const struct streaming_start *ss) +{ + /* TODO: Check our stream still exists? */ + + return 0; +} + + +/* + * Open the muxer as a stream muxer (using a non-seekable socket) + */ +static int +audioes_muxer_open_stream(muxer_t *m, int fd) +{ + audioes_muxer_t *am = (audioes_muxer_t*)m; + + am->am_fd = fd; + am->am_seekable = 0; + am->am_filename = strdup("Live stream"); + + return 0; +} + + +/** + * Open the file and set the file descriptor + */ +static int +audioes_muxer_open_file(muxer_t *m, const char *filename) +{ + int fd; + audioes_muxer_t *am = (audioes_muxer_t*)m; + + tvhtrace(LS_AUDIOES, "Creating file \"%s\" with file permissions \"%o\"", filename, am->m_config.m_file_permissions); + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, am->m_config.m_file_permissions); + + if(fd < 0) { + am->am_error = errno; + tvherror(LS_AUDIOES, "%s: Unable to create file, open failed -- %s", + filename, strerror(errno)); + am->m_errors++; + return -1; + } + + /* bypass umask settings */ + if (fchmod(fd, am->m_config.m_file_permissions)) + tvherror(LS_AUDIOES, "%s: Unable to change permissions -- %s", + filename, strerror(errno)); + + am->am_seekable = 1; + am->am_fd = fd; + am->am_filename = strdup(filename); + return 0; +} + +/** + * Write a packet to the muxer + */ +static int +audioes_muxer_write_pkt(muxer_t *m, streaming_message_type_t smt, void *data) +{ + th_pkt_t *pkt = (th_pkt_t*)data; + audioes_muxer_t *am = (audioes_muxer_t*)m; + + assert(smt == SMT_PACKET); + + // TODO: pkt->pkt_componentindex + /* TODO: ^ What does this even mean? */ + + if(pkt->pkt_componentindex != am->am_index) { + pkt_ref_dec(pkt); + return am->error; + } + + if(am->am_error) { + am->m_errors++; + } else if(tvh_write(am->am_fd, pktbuf_ptr(pkt->pkt_payload), pktbuf_len(pkt->pkt_payload))) { + am->am_error = errno; + tvherror(LS_AUDIOES, "%s: Write failed -- %s", am->am_filename, + strerror(errno)); + /* TODO: Do some EOS handling here. Whatever that is. See muxer_pass.c:415 */ + am->m_errors++; + /* TODO: A muxer_cache_update() call is still missing here. */ + } + + pkt_ref_dec(pkt); + return am->error; +} + + +/** + * NOP + */ +static int +audioes_muxer_write_meta(muxer_t *m, struct epg_broadcast *eb, const char *comment) +{ + return 0; +} + + + +/** + * Close the muxer + */ +static int +audioes_muxer_close(muxer_t *m) +{ + audioes_muxer_t *am = (audioes_muxer_t*)m; + + if ((am->am_seekable) && (close(am->am_fd))) { + am->am_error = errno; + tvherror(LS_AUDIOES, "%s: Unable to close file -- %s", + am->am_filename, strerror(errno)); + am->m_errors++; + return -1; + } + + return 0; +} + + +/** + * Free all memory associated with the muxer + */ +static void +audioes_muxer_destroy(muxer_t *m) +{ + audioes_muxer_t *am = (audioes_muxer_t*)m; + + if(am->am_filename) + free(am->am_filename); + + free(am); +} + + +/** + * Create a new builtin muxer + */ +muxer_t* +audioes_muxer_create(const muxer_config_t *m_cfg) +{ + audioes_muxer_t *am; + + if(m_cfg->m_type != MC_AUDIOES) + return NULL; + + am = calloc(1, sizeof(audioes_muxer_t)); + am->m_open_stream = audioes_muxer_open_stream; + am->m_open_file = audioes_muxer_open_file; + am->m_mime = audioes_muxer_mime; + am->m_init = audioes_muxer_init; + am->m_reconfigure = audioes_muxer_reconfigure; + am->m_write_meta = audioes_muxer_write_meta; + am->m_write_pkt = audioes_muxer_write_pkt; + am->m_close = audioes_muxer_close; + am->m_destroy = audioes_muxer_destroy; + //am->m_container = *m_cfg; //WTF DOES THIS DO?! + + return (muxer_t*)am; +} + diff --git a/src/muxer/muxer_audioes.h b/src/muxer/muxer_audioes.h new file mode 100644 index 000000000..1e4d3c0d0 --- /dev/null +++ b/src/muxer/muxer_audioes.h @@ -0,0 +1,26 @@ +/* + * "muxer" to write raw audio streams + * Copyright (C) 2013 Dave Chapman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef AUDIOES_MUXER_H_ +#define AUDIOES_MUXER_H_ + +#include "muxer.h" + +muxer_t* audioes_muxer_create (const muxer_config_t* m_cfg); + +#endif diff --git a/src/profile.c b/src/profile.c index 3aa1a4c16..fcee69fe1 100644 --- a/src/profile.c +++ b/src/profile.c @@ -1294,6 +1294,83 @@ profile_matroska_builder(void) return (profile_t *)pro; } + +/* + * Audioes Muxer + */ +typedef struct profile_audioes { + profile_t; +} profile_audioes_t; + +const idclass_t profile_audioes_class = +{ + .ic_super = &profile_class, + .ic_class = "profile-audioes", + .ic_caption = N_("Audioes"), + .ic_properties = (const property_t[]){ + { } + } +}; + + +static int +profile_audioes_reopen(profile_chain_t *prch, + muxer_config_t *m_cfg, int flags) +{ + muxer_config_t c; + + if (m_cfg) + c = *m_cfg; /* do not alter the original parameter */ + else + memset(&c, 0, sizeof(c)); + c.m_type = MC_AUDIOES; + + assert(!prch->prch_muxer); + prch->prch_muxer = muxer_create(&c); + return 0; +} + +static int +profile_audioes_open(profile_chain_t *prch, + muxer_config_t *m_cfg, int flags, size_t qsize) +{ + int r; + + prch->prch_flags = SUBSCRIPTION_PACKET; + prch->prch_sq.sq_maxsize = qsize; + + r = profile_htsp_work(prch, &prch->prch_sq.sq_st, 0, 0); + if (r) { + profile_chain_close(prch); + return r; + } + + profile_audioes_reopen(prch, m_cfg, flags); + return 0; +} + +static muxer_container_type_t +profile_audioes_get_mc(profile_t *_pro) +{ + return MC_AUDIOES; +} + +static profile_t * +profile_audioes_builder(void) +{ + profile_audioes_t *pro = calloc(1, sizeof(*pro)); + pro->pro_sflags = SUBSCRIPTION_PACKET; + pro->pro_reopen = profile_audioes_reopen; + pro->pro_open = profile_audioes_open; + pro->pro_get_mc = profile_audioes_get_mc; + return (profile_t *)pro; +} + + + + + + #if ENABLE_LIBAV /* @@ -1564,6 +1641,7 @@ profile_class_mc_list ( void *o, const char *lang ) { N_("WEBM/built-in"), MC_WEBM, }, { N_("MPEG-TS/av-lib"), MC_MPEGTS }, { N_("MPEG-PS (DVD)/av-lib"), MC_MPEGPS }, + { N_("Audioes"), MC_AUDIOES }, { N_("Matroska (mkv)/av-lib"), MC_AVMATROSKA }, { N_("WEBM/av-lib"), MC_AVWEBM }, }; @@ -1959,6 +2037,7 @@ profile_transcode_mc_valid(int mc) case MC_WEBM: case MC_MPEGTS: case MC_MPEGPS: + case MC_AUDIOES: case MC_AVMATROSKA: return 1; default: @@ -2057,6 +2136,7 @@ profile_init(void) profile_register(&profile_mpegts_pass_class, profile_mpegts_pass_builder); profile_register(&profile_matroska_class, profile_matroska_builder); profile_register(&profile_htsp_class, profile_htsp_builder); + profile_register(&profile_audioes_class, profile_audioes_builder); #if ENABLE_LIBAV profile_register(&profile_libav_mpegts_class, profile_libav_mpegts_builder); profile_register(&profile_libav_matroska_class, profile_libav_matroska_builder); @@ -2128,6 +2208,21 @@ profile_init(void) htsmsg_destroy(conf); } + name = "audioes"; + pro = profile_find_by_name2(name, NULL, 1); + if (pro == NULL || strcmp(profile_get_name(pro), name)) { + htsmsg_t *conf; + + conf = htsmsg_create_map(); + htsmsg_add_str (conf, "class", "profile-audioes"); + htsmsg_add_bool(conf, "enabled", 1); + htsmsg_add_str (conf, "name", name); + htsmsg_add_str (conf, "comment", _("Audio-only MPEG elementary stream")); + htsmsg_add_s32 (conf, "priority", PROFILE_SPRIO_NORMAL); + (void)profile_create(NULL, conf, 1); + htsmsg_destroy(conf); + } + #if ENABLE_LIBAV name = "webtv-vp8-vorbis-webm"; diff --git a/src/tvhlog.c b/src/tvhlog.c index 24f0e8eec..a3fab4c84 100644 --- a/src/tvhlog.c +++ b/src/tvhlog.c @@ -122,6 +122,7 @@ tvhlog_subsys_t tvhlog_subsystems[] = { [LS_HEVC] = { "hevc", N_("HEVC - H.265") }, [LS_MUXER] = { "muxer", N_("Muxer") }, [LS_PASS] = { "pass", N_("Pass-thru muxer") }, + [LS_AUDIOES] = { "audioes", N_("Audioes muxer") }, [LS_MKV] = { "mkv", N_("Matroska muxer") }, [LS_SERVICE] = { "service", N_("Service") }, [LS_CHANNEL] = { "channel", N_("Channel") }, diff --git a/src/tvhlog.h b/src/tvhlog.h index d4b277fea..36ffca84d 100644 --- a/src/tvhlog.h +++ b/src/tvhlog.h @@ -146,6 +146,7 @@ enum { LS_HEVC, LS_MUXER, LS_PASS, + LS_AUDIOES, LS_MKV, LS_SERVICE, LS_CHANNEL,