vlc | branch: master | Francois Cartegnie <[email protected]> | Fri Aug 31 18:21:15 2018 +0200| [989a9db6668ca05d158bd6197274bfca81b7c121] | committer: Francois Cartegnie
sout: sdi: add support for audio pairs remapping > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=989a9db6668ca05d158bd6197274bfca81b7c121 --- modules/stream_out/sdi/DBMSDIOutput.cpp | 11 +- modules/stream_out/sdi/DBMSDIOutput.hpp | 1 - modules/stream_out/sdi/SDIAudioMultiplex.cpp | 179 +++++++++++++++++++++++++++ modules/stream_out/sdi/SDIAudioMultiplex.hpp | 10 ++ modules/stream_out/sdi/SDIOutput.cpp | 31 +++-- modules/stream_out/sdi/SDIOutput.hpp | 2 +- modules/stream_out/sdi/sdiout.cpp | 10 ++ 7 files changed, 220 insertions(+), 24 deletions(-) diff --git a/modules/stream_out/sdi/DBMSDIOutput.cpp b/modules/stream_out/sdi/DBMSDIOutput.cpp index d2e602fd36..0818e4fc03 100644 --- a/modules/stream_out/sdi/DBMSDIOutput.cpp +++ b/modules/stream_out/sdi/DBMSDIOutput.cpp @@ -54,7 +54,6 @@ DBMSDIOutput::~DBMSDIOutput() if(video.pic_nosignal) picture_Release(video.pic_nosignal); es_format_Clean(&video.configuredfmt); - es_format_Clean(&audio.configuredfmt); if(p_output) { BMDTimeValue out; @@ -274,15 +273,6 @@ int DBMSDIOutput::ConfigureAudio(const audio_format_t *) { HRESULT result; - audio.configuredfmt.i_codec = - audio.configuredfmt.audio.i_format = VLC_CODEC_S16N; - audio.configuredfmt.audio.i_channels = 2; - audio.configuredfmt.audio.i_physical_channels = AOUT_CHANS_STEREO; - audio.configuredfmt.audio.i_rate = 48000; - audio.configuredfmt.audio.i_bitspersample = 16; - audio.configuredfmt.audio.i_blockalign = 2 * 16 / 8; - //audio.configuredfmt.audio.i_frame_length = BLOCK_SIZE_BYTES; - if(FAKE_DRIVER) return VLC_SUCCESS; @@ -302,6 +292,7 @@ int DBMSDIOutput::ConfigureAudio(const audio_format_t *) maxchannels, bmdAudioOutputStreamTimestamped); CHECK("Could not start audio output"); + audio.b_configured = true; } return VLC_SUCCESS; diff --git a/modules/stream_out/sdi/DBMSDIOutput.hpp b/modules/stream_out/sdi/DBMSDIOutput.hpp index 7c1de10bf2..13a65fd29f 100644 --- a/modules/stream_out/sdi/DBMSDIOutput.hpp +++ b/modules/stream_out/sdi/DBMSDIOutput.hpp @@ -53,7 +53,6 @@ namespace sdi_sout vlc_tick_t lasttimestamp; /* XXX: workaround card clock drift */ vlc_tick_t offset; - bool b_running; int Start(); const char *ErrorToString(long i_code); diff --git a/modules/stream_out/sdi/SDIAudioMultiplex.cpp b/modules/stream_out/sdi/SDIAudioMultiplex.cpp index 35993947c5..4369932f64 100644 --- a/modules/stream_out/sdi/SDIAudioMultiplex.cpp +++ b/modules/stream_out/sdi/SDIAudioMultiplex.cpp @@ -22,7 +22,10 @@ #endif #include "SDIAudioMultiplex.hpp" +#include <vlc_es.h> #include <limits> +#include <cstring> +#include <algorithm> using namespace sdi_sout; @@ -52,10 +55,39 @@ void * SDIAudioMultiplexBuffer::Dequeue() return NULL; } +static void ConfigureChannels(unsigned i, es_format_t *fmt) +{ + if( i>=8 ) + { + i = 8; + fmt->audio.i_physical_channels = AOUT_CHANS_7_1; + } + else if( i>2 ) + { + i = 6; + fmt->audio.i_physical_channels = AOUT_CHANS_5_1; + } + else + { + fmt->audio.i_physical_channels = AOUT_CHANS_STEREO; + } + fmt->audio.i_channels = i; + fmt->audio.i_blockalign = i * 16 / 8; +} + SDIAudioMultiplexConfig::Mapping::Mapping(const StreamID &id) : id(id) { + es_format_Init(&fmt, AUDIO_ES, VLC_CODEC_S16N); + fmt.audio.i_format = VLC_CODEC_S16N; + fmt.audio.i_rate = 48000; + fmt.audio.i_bitspersample = 16; + ConfigureChannels(2, &fmt); +} +SDIAudioMultiplexConfig::Mapping::~Mapping() +{ + es_format_Clean(&fmt); } SDIAudioMultiplexConfig::SDIAudioMultiplexConfig(uint8_t channels) @@ -67,6 +99,7 @@ SDIAudioMultiplexConfig::SDIAudioMultiplexConfig(uint8_t channels) framewidth = 4; else framewidth = 1; + b_accept_any = true; } SDIAudioMultiplexConfig::~SDIAudioMultiplexConfig() @@ -85,6 +118,98 @@ void SDIAudioMultiplexConfig::setSubFrameSlotUsed(uint8_t i) subframeslotbitmap |= (1 << i); } +void SDIAudioMultiplexConfig::parseConfiguration(vlc_object_t *obj, const char *psz) +{ + char *name = NULL; + char *psz_in = (char*)psz; + config_chain_t *p_config_chain = NULL; + while(psz_in) + { + char *psz_next = config_ChainCreate(&name, &p_config_chain, psz_in); + if(name) + { + if(!std::strcmp(name, "only")) + { + b_accept_any = false; + msg_Dbg(obj, "only accepting declared streams"); + } + else /* try mapping decl */ + { + int i_id = -1; + int i_seqid = -1; + int *pi_id = &i_seqid; + const char *psz_id = name; + if(psz_id[0]=='#') + { + psz_id++; + pi_id = &i_id; + } + if(*psz_id) + { + char *end = NULL; + int i_val = std::strtol(psz_id, &end, 10); + if(end != NULL && *end == '\0') + *pi_id = i_val; + } + if(i_id != -1 || i_seqid != -1) + { + msg_Dbg(obj,"found declaration for ES %s %d", + (i_id > -1) ? "pid #" : "seq", *pi_id); + int i_reserved_chans = 0; + std::vector<uint8_t> subframeslots; + for(config_chain_t *p = p_config_chain; p; p = p->p_next) + { + if(!std::strcmp("chans", p->psz_name) && subframeslots.empty()) + { + char *end = NULL; + int i_val = std::strtol(p->psz_value, &end, 10); + if(end != NULL && *end == '\0') + { + i_reserved_chans = i_val; + msg_Dbg(obj," * provisioned %d channels", i_val); + } + else msg_Warn(obj, " * ignoring channels count declaration %d", i_val); + } + else if(i_reserved_chans == 0) + { + char *end = NULL; + int i_slot = std::strtol(p->psz_name, &end, 10); + if(end != NULL && *end == '\0') + { + if(i_slot < MAX_AES3_AUDIO_SUBFRAMES && i_slot < (2 * framewidth) && + std::find(subframeslots.begin(), subframeslots.end(), i_slot) == subframeslots.end()) + { + subframeslots.push_back(i_slot); + msg_Dbg(obj," * mapped channel %zd to subframe %d", + subframeslots.size(), i_slot); + } + else msg_Warn(obj, " * ignoring invalid subframe declaration %d", i_slot); + } + else msg_Warn(obj, " * ignoring unknown/invalid token %s", p->psz_name); + } + } + + bool b_success = false; + if(subframeslots.empty() && i_reserved_chans) + b_success = addMapping(StreamID(i_id, i_seqid), i_reserved_chans); + else if(!subframeslots.empty()) + b_success = addMapping(StreamID(i_id, i_seqid), subframeslots); + + if(b_success) + msg_Dbg(obj, " * successfully configured"); + else + msg_Warn(obj, " * configuration rejected (duplicate or not enough subframes ?)"); + } + } + free(name); + } + config_ChainDestroy(p_config_chain); + if(psz != psz_in) + free(psz_in); + psz_in = psz_next; + } +} + std::vector<uint8_t> SDIAudioMultiplexConfig::getFreeSubFrameSlots() const { std::vector<uint8_t> slots; @@ -97,6 +222,32 @@ std::vector<uint8_t> SDIAudioMultiplexConfig::getFreeSubFrameSlots() const return slots; } +std::vector<uint8_t> SDIAudioMultiplexConfig::getConfiguredSlots(const StreamID &id) const +{ + for(size_t i=0; i<mappings.size(); i++) + { + if(mappings[i]->id == id) + return mappings[i]->subframesslots; + } + return std::vector<uint8_t>(); +} + +bool SDIAudioMultiplexConfig::addMapping(const StreamID &id, const es_format_t *fmt) +{ + if(!fmt->audio.i_channels || !b_accept_any) + return false; + return addMapping(id, fmt->audio.i_channels); +} + +bool SDIAudioMultiplexConfig::addMapping(const StreamID &id, unsigned channels) +{ + std::vector<uint8_t> slots = getFreeSubFrameSlots(); + if(slots.size() < channels) + return false; + slots.resize(channels); + return addMapping(id, slots); +} + bool SDIAudioMultiplexConfig::addMapping(const StreamID &id, std::vector<uint8_t> subframeslots) { for(size_t i=0; i<mappings.size(); i++) @@ -111,6 +262,9 @@ bool SDIAudioMultiplexConfig::addMapping(const StreamID &id, std::vector<uint8_t mappings.push_back(assoc); + for(size_t i=0; i<subframeslots.size(); i++) + setSubFrameSlotUsed(subframeslots[i]); + return true; } @@ -130,6 +284,31 @@ SDIAudioMultiplexBuffer * return NULL; } +const es_format_t * SDIAudioMultiplexConfig::getConfigurationForStream(const StreamID &id) const +{ + auto it = std::find_if(mappings.begin(), mappings.end(), + [&id](Mapping *e) { return e->id == id; }); + return (it != mappings.end()) ? &(*it)->fmt : NULL; +} + +const es_format_t * + SDIAudioMultiplexConfig::updateFromRealESConfig(const StreamID &id, + const es_format_t *fmt) +{ + auto it = std::find_if(mappings.begin(), mappings.end(), + [&id](Mapping *e) { return e->id == id; }); + if(it != mappings.end()) + { + Mapping *mapping = (*it); + if(mapping->subframesslots.size() > 2 && fmt->audio.i_channels > 2) + ConfigureChannels(fmt->audio.i_channels, &mapping->fmt); + mapping->buffer.setSubFramesCount(mapping->fmt.audio.i_channels); + return &mapping->fmt; + } + assert(0); + return NULL; +} + SDIAudioMultiplex::SDIAudioMultiplex(uint8_t channels) { config = SDIAudioMultiplexConfig(channels); diff --git a/modules/stream_out/sdi/SDIAudioMultiplex.hpp b/modules/stream_out/sdi/SDIAudioMultiplex.hpp index 7606b3d2e6..a571cf689f 100644 --- a/modules/stream_out/sdi/SDIAudioMultiplex.hpp +++ b/modules/stream_out/sdi/SDIAudioMultiplex.hpp @@ -46,26 +46,36 @@ namespace sdi_sout SDIAudioMultiplexConfig(uint8_t channels = 2); ~SDIAudioMultiplexConfig(); SDIAudioMultiplexBuffer *getBufferForStream(const StreamID &); + const es_format_t * getConfigurationForStream(const StreamID &) const; + const es_format_t * updateFromRealESConfig(const StreamID &, + const es_format_t *); bool SubFrameSlotUsed(uint8_t) const; void setSubFrameSlotUsed(uint8_t); + void parseConfiguration(vlc_object_t *, const char *); uint8_t getMultiplexedFramesCount() const { return framewidth; } std::vector<uint8_t> getFreeSubFrameSlots() const; + std::vector<uint8_t> getConfiguredSlots(const StreamID &) const; + bool addMapping(const StreamID &, const es_format_t *); bool addMapping(const StreamID &, std::vector<uint8_t>); unsigned getMaxSamplesForBlockSize(size_t) const; private: + bool addMapping(const StreamID &, unsigned); class Mapping { public: Mapping(const StreamID &); + ~Mapping(); StreamID id; + es_format_t fmt; SDIAudioMultiplexBuffer buffer; std::vector<uint8_t> subframesslots; }; std::vector<Mapping *> mappings; unsigned subframeslotbitmap; uint8_t framewidth; + bool b_accept_any; }; class SDIAudioMultiplex diff --git a/modules/stream_out/sdi/SDIOutput.cpp b/modules/stream_out/sdi/SDIOutput.cpp index fce8a00d77..f3ee7f7d7a 100644 --- a/modules/stream_out/sdi/SDIOutput.cpp +++ b/modules/stream_out/sdi/SDIOutput.cpp @@ -42,11 +42,11 @@ SDIOutput::SDIOutput(sout_stream_t *p_stream_) p_stream->pace_nocontrol = true; es_format_Init(&video.configuredfmt, VIDEO_ES, 0); - es_format_Init(&audio.configuredfmt, AUDIO_ES, 0); video.tenbits = var_InheritBool(p_stream, CFG_PREFIX "tenbits"); video.nosignal_delay = var_InheritInteger(p_stream, CFG_PREFIX "nosignal-delay"); video.pic_nosignal = NULL; audio.i_channels = var_InheritInteger(p_stream, CFG_PREFIX "channels");; + audio.b_configured = false; ancillary.afd = var_InheritInteger(p_stream, CFG_PREFIX "afd"); ancillary.ar = var_InheritInteger(p_stream, CFG_PREFIX "ar"); ancillary.afd_line = var_InheritInteger(p_stream, CFG_PREFIX "afd-line"); @@ -54,6 +54,12 @@ SDIOutput::SDIOutput(sout_stream_t *p_stream_) videoStream = NULL; captionsStream = NULL; audioMultiplex = new SDIAudioMultiplex( var_InheritInteger(p_stream, CFG_PREFIX "channels") ); + char *psz_channelsconf = var_InheritString(p_stream, CFG_PREFIX "audio"); + if(psz_channelsconf) + { + audioMultiplex->config.parseConfiguration(VLC_OBJECT(p_stream), psz_channelsconf); + free(psz_channelsconf); + } } SDIOutput::~SDIOutput() @@ -69,7 +75,6 @@ SDIOutput::~SDIOutput() if(video.pic_nosignal) picture_Release(video.pic_nosignal); es_format_Clean(&video.configuredfmt); - es_format_Clean(&audio.configuredfmt); } AbstractStream *SDIOutput::Add(const es_format_t *fmt) @@ -88,27 +93,29 @@ AbstractStream *SDIOutput::Add(const es_format_t *fmt) } else if(fmt->i_cat == AUDIO_ES && audio.i_channels) { - if(audio.configuredfmt.i_codec || ConfigureAudio(&fmt->audio) == VLC_SUCCESS) + if(audio.b_configured || ConfigureAudio(&fmt->audio) == VLC_SUCCESS) { - std::vector<uint8_t> slots = audioMultiplex->config.getFreeSubFrameSlots(); - if(slots.size() < 2) - return NULL; - slots.resize(2); - if(!audioMultiplex->config.addMapping(id, slots)) - return NULL; + const es_format_t *cfgfmt = audioMultiplex->config.getConfigurationForStream(id); + if(!cfgfmt) + { + if(!audioMultiplex->config.addMapping(id, fmt)) + return NULL; + } + cfgfmt = audioMultiplex->config.updateFromRealESConfig(id, fmt); SDIAudioMultiplexBuffer *buffer = audioMultiplex->config.getBufferForStream(id); if(!buffer) return NULL; - AudioDecodedStream *audioStream; s = audioStream = dynamic_cast<AudioDecodedStream *>(createStream(id, fmt, buffer)); if(audioStream) { - audioStream->setOutputFormat(&audio.configuredfmt); + audioStream->setOutputFormat(cfgfmt); audioStreams.push_back(audioStream); + std::vector<uint8_t> slots = audioMultiplex->config.getConfiguredSlots(id); for(size_t i=0; i<slots.size(); i++) { - audioMultiplex->config.setSubFrameSlotUsed(slots[i]); + msg_Dbg(p_stream, "%s slot %d to read from channel %zd", + id.toString().c_str(), slots[i], i); audioMultiplex->SetSubFrameSource(slots[i], buffer, AES3AudioSubFrameIndex(i)); } } diff --git a/modules/stream_out/sdi/SDIOutput.hpp b/modules/stream_out/sdi/SDIOutput.hpp index c2fb2d77d4..290f2a315b 100644 --- a/modules/stream_out/sdi/SDIOutput.hpp +++ b/modules/stream_out/sdi/SDIOutput.hpp @@ -64,8 +64,8 @@ namespace sdi_sout struct { - es_format_t configuredfmt; uint8_t i_channels; + bool b_configured; } audio; struct diff --git a/modules/stream_out/sdi/sdiout.cpp b/modules/stream_out/sdi/sdiout.cpp index eb450cfb10..c7b3f88200 100644 --- a/modules/stream_out/sdi/sdiout.cpp +++ b/modules/stream_out/sdi/sdiout.cpp @@ -75,6 +75,15 @@ #define VIDEO_TENBITS_LONGTEXT N_(\ "Use 10 bits per pixel for video frames.") +#define AUDIO_TEXT "Audio channels configuration (Default, single, auto)" +#define AUDIO_LONGTEXT "Configuration string SEL{CHANS} tokens, ':' separated. " \ + "SEL selectors being #145 for ES id 145, or 1 for second created ES. " \ + "CHANS being {n,n+1,..} channels to subframe mapping. " \ + "{chans=6} shortcut to request 6 channels in same order. " \ + "Use 'only' to accept only declared ES. " \ + "ex: only:#145{0,1}:#142{2,3}:2{chans=6} " + + /* Video Connections */ static const char *const ppsz_videoconns[] = { "sdi", @@ -201,5 +210,6 @@ vlc_module_begin () set_section(N_("DeckLink Audio Options"), NULL) add_integer_with_range(CFG_PREFIX "channels", 2, 0, 16, CHANNELS_TEXT, CHANNELS_LONGTEXT, true) + add_string(CFG_PREFIX "audio", "", AUDIO_TEXT, AUDIO_LONGTEXT, true) vlc_module_end () _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
