diff options
author | Michele Calgaro <michele.calgaro@yahoo.it> | 2022-05-30 19:40:31 +0900 |
---|---|---|
committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2022-05-31 01:17:58 +0900 |
commit | d95a4fea540b371fa86493d069fdbd54f33c5b40 (patch) | |
tree | 079b038ab559439eb7ded40a07bd79fd92926b3b /plugins/recording/encoder_ogg.cpp | |
parent | e54890e0480e5adee69f5220a7c6dd072bbd75ea (diff) | |
download | tderadio-d95a4fea540b371fa86493d069fdbd54f33c5b40.tar.gz tderadio-d95a4fea540b371fa86493d069fdbd54f33c5b40.zip |
Standardize folder structure.
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'plugins/recording/encoder_ogg.cpp')
-rw-r--r-- | plugins/recording/encoder_ogg.cpp | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/plugins/recording/encoder_ogg.cpp b/plugins/recording/encoder_ogg.cpp new file mode 100644 index 0000000..ca093b9 --- /dev/null +++ b/plugins/recording/encoder_ogg.cpp @@ -0,0 +1,250 @@ +/*************************************************************************** + encoder_ogg.cpp + ------------------- + begin : Sat Aug 20 2005 + copyright : (C) 2005 by Martin Witte + email : witte@kawo1.rwth-aachen.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "encoder_ogg.h" + +#include <tdelocale.h> +#include <stdlib.h> + +RecordingEncodingOgg::RecordingEncodingOgg(TQObject *parent, SoundStreamID ssid, + const RecordingConfig &cfg, const RadioStation *rs, + const TQString &filename) + : RecordingEncoding(parent, ssid, cfg, rs, filename) +#ifdef HAVE_OGG + , + m_OggOutput(NULL), + m_OggExportBuffer(NULL), + m_OggExportBufferSize(0) +#endif +{ + m_config.m_OutputFormat = RecordingConfig::outputOGG; + m_config.m_SoundFormat.m_Encoding = "ogg"; + openOutput(filename); +} + + +RecordingEncodingOgg::~RecordingEncodingOgg() +{ + closeOutput(); +} + +void RecordingEncodingOgg::encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size) +{ + if (m_error) + return; + +#ifdef HAVE_OGG + SoundFormat &sf = m_config.m_SoundFormat; + ogg_page ogg_pg; + ogg_packet ogg_pkt; + + size_t samples = buffer_size / sf.frameSize(); + + // buffer[channel][sample], normalized to -1..0..+1 + float **buffer = vorbis_analysis_buffer(&m_VorbisDSP, (samples < 512 ? 512 : samples)); + + sf.convertSamplesToFloat(_buffer, buffer, samples); + + /* Tell the library how many samples (per channel) we wrote + into the supplied buffer */ + vorbis_analysis_wrote(&m_VorbisDSP, samples); + + /* While we can get enough data from the library to analyse, one + block at a time... */ + + bool eos = false; + while(!m_error && !eos && vorbis_analysis_blockout(&m_VorbisDSP, &m_VorbisBlock) == 1) { + + /* Do the main analysis, creating a packet */ + vorbis_analysis(&m_VorbisBlock, NULL); + vorbis_bitrate_addblock(&m_VorbisBlock); + + while(!m_error && vorbis_bitrate_flushpacket(&m_VorbisDSP, &ogg_pkt)) { + /* Add packet to bitstream */ + ogg_stream_packetin(&m_OggStream,&ogg_pkt); + + /* If we've gone over a page boundary, we can do actual output, + so do so (for however many pages are available) */ + + while(!m_error && !eos) { + int result = ogg_stream_pageout(&m_OggStream, &ogg_pg); + if (!result) break; + + int n = fwrite(ogg_pg.header, 1, ogg_pg.header_len, m_OggOutput); + n += fwrite(ogg_pg.body, 1, ogg_pg.body_len, m_OggOutput); + + m_encodedSize += n; + + if (n != (ogg_pg.header_len + ogg_pg.body_len)) { + m_error = true; + m_errorString += i18n("Failed writing data to ogg/vorbis output stream. "); + break; + } else { + + if (m_OggExportBufferSize < export_buffer_size + n) { + m_OggExportBuffer = (char*)realloc(m_OggExportBuffer, m_OggExportBufferSize + 2 * n); + m_OggExportBufferSize += 2 * n; + } + + memcpy (m_OggExportBuffer + export_buffer_size, ogg_pg.header, ogg_pg.header_len); + export_buffer_size += ogg_pg.header_len; + memcpy (m_OggExportBuffer + export_buffer_size, ogg_pg.body, ogg_pg.body_len); + export_buffer_size += ogg_pg.body_len; + + } + if (ogg_page_eos(&ogg_pg)) + eos = 1; + } + } + } + + export_buffer = m_OggExportBuffer; +#endif +} + + +#ifdef HAVE_OGG +static void vorbis_comment_add_tag_new(vorbis_comment *vc, const TQString &tag, const TQString &value) +{ + char *stag = strdup(tag.ascii()); + char *svalue = strdup(value.utf8()); + vorbis_comment_add_tag(vc, stag, svalue); + delete stag; + delete svalue; +} +#endif + +bool RecordingEncodingOgg::openOutput(const TQString &output) +{ +#ifdef HAVE_OGG + m_OggOutput = fopen(output.ascii(), "wb+"); + if (!m_OggOutput) { + m_errorString += i18n("Cannot open Ogg/Vorbis output file %1. ").arg(output); + m_error = true; + } + + m_OggExportBuffer = (char*)malloc(m_OggExportBufferSize = 65536); // start with a 64k buffer + + + /* Have vorbisenc choose a mode for us */ + vorbis_info_init(&m_VorbisInfo); + + SoundFormat &sf = m_config.m_SoundFormat; + if (vorbis_encode_setup_vbr(&m_VorbisInfo, sf.m_Channels, sf.m_SampleRate, m_config.m_oggQuality)) { + m_error = true; + m_errorString = i18n("Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n"); + vorbis_info_clear(&m_VorbisInfo); + return false; + } + + /* Turn off management entirely (if it was turned on). */ + vorbis_encode_ctl(&m_VorbisInfo, OV_ECTL_RATEMANAGE_SET, NULL); + vorbis_encode_setup_init(&m_VorbisInfo); + + /* Now, set up the analysis engine, stream encoder, and other + preparation before the encoding begins. + */ + + vorbis_analysis_init(&m_VorbisDSP, &m_VorbisInfo); + vorbis_block_init(&m_VorbisDSP, &m_VorbisBlock); + + ogg_stream_init (&m_OggStream, m_SoundStreamID.getID()); + + /* Now, build the three header packets and send through to the stream + output stage (but defer actual file output until the main encode loop) */ + + ogg_packet header_main; + ogg_packet header_comments; + ogg_packet header_codebooks; + + /* Build the packets */ + vorbis_comment vc; + vorbis_comment_init (&vc); + vorbis_comment_add_tag_new(&vc, "creator", "TDERadio" VERSION); + vorbis_comment_add_tag_new(&vc, "title", m_RadioStation->longName().utf8()); + vorbis_comment_add_tag_new(&vc, "date", TQDateTime::currentDateTime().toString(Qt::ISODate)); + + vorbis_analysis_headerout(&m_VorbisDSP, &vc, + &header_main, &header_comments, &header_codebooks); + + /* And stream them out */ + ogg_stream_packetin(&m_OggStream, &header_main); + ogg_stream_packetin(&m_OggStream, &header_comments); + ogg_stream_packetin(&m_OggStream, &header_codebooks); + + int result; + ogg_page ogg_page; + while((result = ogg_stream_flush(&m_OggStream, &ogg_page))) { + + if (!result) break; + + int n = fwrite(ogg_page.header, 1, ogg_page.header_len, m_OggOutput); + n += fwrite(ogg_page.body, 1, ogg_page.body_len, m_OggOutput); + + if(n != ogg_page.header_len + ogg_page.body_len) { + m_error = true; + m_errorString += i18n("Failed writing Ogg/Vorbis header to output stream\n"); + break; + } + } + + vorbis_comment_clear (&vc); + + if (m_error) { + if (m_OggOutput) fclose (m_OggOutput); + m_OggOutput = NULL; + free(m_OggExportBuffer); + m_OggExportBuffer = NULL; + m_OggExportBufferSize = 0; + + ogg_stream_clear(&m_OggStream); + vorbis_block_clear(&m_VorbisBlock); + vorbis_dsp_clear(&m_VorbisDSP); + vorbis_info_clear(&m_VorbisInfo); + } + + return !m_error; +#endif +} + + +void RecordingEncodingOgg::closeOutput() +{ +#ifdef HAVE_OGG + if (m_OggOutput) { + + char *tmp_buf = NULL; + size_t tmp_size = 0; + // flush buffer + encode(tmp_buf, tmp_size, tmp_buf, tmp_size); + + fclose(m_OggOutput); + m_OggOutput = NULL; + + free(m_OggExportBuffer); + m_OggExportBuffer = NULL; + m_OggExportBufferSize = 0; + + ogg_stream_clear(&m_OggStream); + vorbis_block_clear(&m_VorbisBlock); + vorbis_dsp_clear(&m_VorbisDSP); + vorbis_info_clear(&m_VorbisInfo); + } +#endif +} + + |