kwave  18.07.70
Kwave::OpusEncoder Class Reference

#include <OpusEncoder.h>

Inheritance diagram for Kwave::OpusEncoder:
Inheritance graph
Collaboration diagram for Kwave::OpusEncoder:
Collaboration graph

Public Member Functions

 OpusEncoder ()
 
virtual ~OpusEncoder () Q_DECL_OVERRIDE
 
virtual bool open (QWidget *widget, const Kwave::FileInfo &info, Kwave::MultiTrackReader &src) Q_DECL_OVERRIDE
 
virtual bool writeHeader (QIODevice &dst) Q_DECL_OVERRIDE
 
virtual bool encode (Kwave::MultiTrackReader &src, QIODevice &dst) Q_DECL_OVERRIDE
 
virtual void close () Q_DECL_OVERRIDE
 
- Public Member Functions inherited from Kwave::OggSubEncoder
virtual ~OggSubEncoder ()
 

Private Types

enum  { DOWNMIX_OFF = -1, DOWNMIX_AUTO = 0, DOWNMIX_MONO = 1, DOWNMIX_STEREO = 2 }
 

Private Member Functions

bool setupDownMix (QWidget *widget, unsigned int tracks, int bitrate)
 
bool setupBitrate (QWidget *widget, unsigned int tracks)
 
bool setupCodingRate (QWidget *widget, unsigned int tracks, double rate)
 
bool setupEncoder (QWidget *widget, unsigned int tracks, double rate)
 
bool setupBitrateMode (QWidget *widget)
 
bool writeOpusHeader (QIODevice &dst)
 
bool writeOpusTags (QIODevice &dst)
 
bool writeOggPage (QIODevice &dst)
 
unsigned int fillInBuffer (Kwave::MultiTrackReader &src)
 

Private Attributes

Kwave::VorbisCommentMap m_comments_map
 
Kwave::FileInfo m_info
 
ogg_stream_state m_os
 
ogg_page m_og
 
ogg_packet m_op
 
enum Kwave::OpusEncoder:: { ... }  m_downmix
 
int m_bitrate
 
int m_coding_rate
 
unsigned int m_encoder_channels
 
Kwave::ChannelMixerm_channel_mixer
 
Kwave::StreamObjectm_rate_converter
 
unsigned int m_frame_size
 
unsigned int m_extra_out
 
Kwave::opus_header_t m_opus_header
 
unsigned int m_max_frame_bytes
 
unsigned char * m_packet_buffer
 
OpusMSEncoder * m_encoder
 
float * m_encoder_input
 
Kwave::StreamObjectm_last_queue_element
 
Kwave::MultiTrackSink< Kwave::SampleBuffer, true > * m_buffer
 

Detailed Description

Definition at line 47 of file OpusEncoder.h.

Member Enumeration Documentation

◆ anonymous enum

anonymous enum
private

downmix mode: off, automatic, mono or stereo

Enumerator
DOWNMIX_OFF 

no downmixing

DOWNMIX_AUTO 

automatic, based on bitrate

DOWNMIX_MONO 

downmix to mono

DOWNMIX_STEREO 

downmix to stereo

Definition at line 183 of file OpusEncoder.h.

Constructor & Destructor Documentation

◆ OpusEncoder()

Kwave::OpusEncoder::OpusEncoder ( )

Constructor

Definition at line 96 of file OpusEncoder.cpp.

References m_opus_header.

97  :m_comments_map(),
98  m_info(),
100  m_bitrate(0),
101  m_coding_rate(0),
103  m_channel_mixer(Q_NULLPTR),
104  m_rate_converter(Q_NULLPTR),
105  m_frame_size(0),
106  m_extra_out(0),
107  m_opus_header(),
109  m_packet_buffer(Q_NULLPTR),
110  m_encoder(Q_NULLPTR),
111  m_encoder_input(Q_NULLPTR),
112  m_last_queue_element(Q_NULLPTR),
113  m_buffer(Q_NULLPTR)
114 {
115 
116  memset(&m_opus_header, 0x00, sizeof(m_opus_header));
117  memset(&m_opus_header.map, 0xFF, sizeof(m_opus_header.map));
118 }
Kwave::opus_header_t m_opus_header
Definition: OpusEncoder.h:212
Kwave::StreamObject * m_rate_converter
Definition: OpusEncoder.h:203
Kwave::FileInfo m_info
Definition: OpusEncoder.h:169
Kwave::VorbisCommentMap m_comments_map
Definition: OpusEncoder.h:166
float * m_encoder_input
Definition: OpusEncoder.h:224
unsigned int m_extra_out
Definition: OpusEncoder.h:209
Kwave::MultiTrackSink< Kwave::SampleBuffer, true > * m_buffer
Definition: OpusEncoder.h:234
unsigned int m_encoder_channels
Definition: OpusEncoder.h:197
unsigned int m_max_frame_bytes
Definition: OpusEncoder.h:215
Kwave::ChannelMixer * m_channel_mixer
Definition: OpusEncoder.h:200
Kwave::StreamObject * m_last_queue_element
Definition: OpusEncoder.h:231
unsigned int m_frame_size
Definition: OpusEncoder.h:206
unsigned char * m_packet_buffer
Definition: OpusEncoder.h:218
OpusMSEncoder * m_encoder
Definition: OpusEncoder.h:221
enum Kwave::OpusEncoder::@12 m_downmix

◆ ~OpusEncoder()

Kwave::OpusEncoder::~OpusEncoder ( )
virtual

Destructor

Definition at line 121 of file OpusEncoder.cpp.

122 {
123 }

Member Function Documentation

◆ close()

void Kwave::OpusEncoder::close ( )
virtual

finished the encoding, clean up

Implements Kwave::OggSubEncoder.

Definition at line 974 of file OpusEncoder.cpp.

References m_buffer, m_channel_mixer, m_encoder, m_encoder_input, m_last_queue_element, m_os, m_packet_buffer, and m_rate_converter.

975 {
976  if (m_channel_mixer) delete m_channel_mixer;
977  m_channel_mixer = Q_NULLPTR;
978 
980  m_rate_converter = Q_NULLPTR;
981 
982  if (m_buffer) delete m_buffer;
983  m_buffer = Q_NULLPTR;
984 
985  if (m_encoder) opus_multistream_encoder_destroy(m_encoder);
986  m_encoder = Q_NULLPTR;
987 
988  ogg_stream_clear(&m_os);
989 
990  if (m_packet_buffer) free(m_packet_buffer);
991  m_packet_buffer = Q_NULLPTR;
992 
993  if (m_encoder_input) free(m_encoder_input);
994  m_encoder_input = Q_NULLPTR;
995 
996  m_last_queue_element = Q_NULLPTR;
997 }
Kwave::StreamObject * m_rate_converter
Definition: OpusEncoder.h:203
float * m_encoder_input
Definition: OpusEncoder.h:224
Kwave::MultiTrackSink< Kwave::SampleBuffer, true > * m_buffer
Definition: OpusEncoder.h:234
Kwave::ChannelMixer * m_channel_mixer
Definition: OpusEncoder.h:200
Kwave::StreamObject * m_last_queue_element
Definition: OpusEncoder.h:231
ogg_stream_state m_os
Definition: OpusEncoder.h:172
unsigned char * m_packet_buffer
Definition: OpusEncoder.h:218
OpusMSEncoder * m_encoder
Definition: OpusEncoder.h:221

◆ encode()

bool Kwave::OpusEncoder::encode ( Kwave::MultiTrackReader src,
QIODevice &  dst 
)
virtual

encode received ogg data

Parameters
srcMultiTrackReader used as source of the audio data
dsta QIODevice that receives the raw data
Returns
true if succeeded, false if failed

Implements Kwave::OggSubEncoder.

Definition at line 829 of file OpusEncoder.cpp.

References DBG, fillInBuffer(), Kwave::MultiTrackReader::isCanceled(), Kwave::FileInfo::length(), m_coding_rate, m_encoder, m_encoder_channels, m_encoder_input, m_frame_size, m_info, m_max_frame_bytes, m_og, m_op, m_opus_header, m_os, m_packet_buffer, Kwave::opus_error(), Kwave::FileInfo::rate(), Kwave::toUint(), and writeOggPage().

831 {
832  long int eos = 0;
833  opus_int64 nb_encoded = 0;
834  opus_int64 nb_samples = -1;
835  opus_int64 total_bytes = 0;
836  opus_int64 total_samples = 0;
837  ogg_int64_t enc_granulepos = 0;
838  ogg_int64_t last_granulepos = 0;
839  ogg_int32_t packet_id = 1;
840  int last_segments = 0;
841  const int max_ogg_delay = 48000; /* 48kHz samples */
842 
843  Q_ASSERT(m_encoder);
844  Q_ASSERT(m_encoder_input);
845 
846  Q_UNUSED(dst);
847 
848  /* Main encoding loop (one frame per iteration) */
849  while (!m_op.e_o_s && !src.isCanceled()) {
850  int size_segments = 0;
851 
852  packet_id++;
853 
854  if (nb_samples < 0) {
855  nb_samples = fillInBuffer(src);
856  total_samples += nb_samples;
857  m_op.e_o_s = (nb_samples < m_frame_size) ? 1 : 0;
858  }
859  m_op.e_o_s |= eos; // eof from last pass
860 
861  // pad the rest of the frame with zeroes if necessary
862  if (nb_samples < m_frame_size ) {
863  const unsigned int pad_from =
864  Kwave::toUint(nb_samples * m_encoder_channels);
865  const unsigned int pad_to =
867  for (unsigned int pos = pad_from; pos < pad_to; pos++ )
868  m_encoder_input[pos] = 0;
869  }
870 
871  /* encode current frame */
872  int nbBytes = opus_multistream_encode_float(
873  m_encoder,
875  m_frame_size,
878  );
879  if (nbBytes < 0 ) {
880  qWarning("Opus encoder failed: '%s'",
881  DBG(Kwave::opus_error(nbBytes)));
882  return false;
883  }
884 
885  nb_encoded += m_frame_size;
886  enc_granulepos += m_frame_size * 48000 / m_coding_rate;
887  total_bytes += nbBytes;
888  size_segments = (nbBytes + 255) / 255;
889 
890  // flush early if adding this packet would make us end up with a
891  // continued page which we wouldn't have otherwise
892  while (( ((size_segments <= 255) &&
893  (last_segments + size_segments > 255)) ||
894  (enc_granulepos - last_granulepos > max_ogg_delay)) &&
895 #ifdef HAVE_OGG_STREAM_FLUSH_FILL
896  ogg_stream_flush_fill(&m_os, &m_og, 255 * 255))
897 #else /* HAVE_OGG_STREAM_FLUSH_FILL */
898  ogg_stream_flush(&m_os, &m_og))
899 #endif /* HAVE_OGG_STREAM_FLUSH_FILL */
900  {
901  if (ogg_page_packets(&m_og) != 0)
902  last_granulepos = ogg_page_granulepos(&m_og);
903 
904  last_segments -= m_og.header[26];
905 
906  if (!writeOggPage(dst)) {
907  qWarning("Opus encoder: I/O error");
908  return false;
909  }
910  }
911 
912  // the downside of early reading is if the input is an exact
913  // multiple of the frame_size you'll get an extra frame that needs
914  // to get cropped off. The downside of late reading is added delay.
915  // If your ogg_delay is 120ms or less we'll assume you want the
916  // low delay behavior.
917  if ((!m_op.e_o_s ) && (max_ogg_delay > 5760)) {
918  nb_samples = fillInBuffer(src);
919  total_samples += nb_samples;
920  if (nb_samples < m_frame_size) eos = 1;
921  if (nb_samples == 0) m_op.e_o_s = 1;
922  } else {
923  nb_samples = -1;
924  }
925 
926  m_op.packet = m_packet_buffer;
927  m_op.packetno = packet_id;
928  m_op.bytes = nbBytes;
929  m_op.b_o_s = 0;
930  m_op.granulepos = enc_granulepos;
931  if (m_op.e_o_s) {
932  // compute the final GP as ceil(len*48k/input_rate). When a
933  // resampling decoder does the matching floor(len*input/48k)
934  // conversion the length will be exactly the same as the input.
935  sample_index_t length = m_info.length();
936  double rate = m_info.rate();
937  m_op.granulepos = static_cast<ogg_int64_t>(
938  ceil((length * 48000.0) / rate) + m_opus_header.preskip);
939  }
940  ogg_stream_packetin(&m_os, &m_op);
941  last_segments += size_segments;
942 
943  // If the stream is over or we're sure that the delayed flush will
944  // fire, go ahead and flush now to avoid adding delay.
945  while ((m_op.e_o_s || (enc_granulepos +
946  ((m_frame_size * 48000) / m_coding_rate ) -
947  last_granulepos > max_ogg_delay) || (last_segments >= 255)) ?
948 #ifdef HAVE_OGG_STREAM_FLUSH_FILL
949  ogg_stream_flush_fill(&m_os, &m_og, 255 * 255) :
950  ogg_stream_pageout_fill(&m_os, &m_og, 255 * 255))
951 #else /* HAVE_OGG_STREAM_FLUSH_FILL */
952  /*Libogg > 1.2.2 allows us to achieve lower overhead by
953  producing larger pages. For 20ms frames this is only relevant
954  above ~32kbit/sec.*/
955  ogg_stream_flush(&m_os, &m_og) :
956  ogg_stream_pageout(&m_os, &m_og))
957 #endif /* HAVE_OGG_STREAM_FLUSH_FILL */
958  {
959  if (ogg_page_packets(&m_og) != 0)
960  last_granulepos = ogg_page_granulepos(&m_og);
961 
962  last_segments -= m_og.header[26];
963  if (!writeOggPage(dst)) {
964  qWarning("Opus encoder: I/O error");
965  return false;
966  }
967  }
968  }
969 
970  return true;
971 }
Kwave::opus_header_t m_opus_header
Definition: OpusEncoder.h:212
unsigned int fillInBuffer(Kwave::MultiTrackReader &src)
double rate() const
Definition: FileInfo.cpp:415
Kwave::FileInfo m_info
Definition: OpusEncoder.h:169
bool writeOggPage(QIODevice &dst)
quint64 sample_index_t
Definition: Sample.h:28
float * m_encoder_input
Definition: OpusEncoder.h:224
unsigned int m_encoder_channels
Definition: OpusEncoder.h:197
sample_index_t length() const
Definition: FileInfo.cpp:400
unsigned int m_max_frame_bytes
Definition: OpusEncoder.h:215
QString opus_error(int err)
Definition: OpusCommon.cpp:45
unsigned int m_frame_size
Definition: OpusEncoder.h:206
ogg_stream_state m_os
Definition: OpusEncoder.h:172
#define DBG(qs)
Definition: String.h:55
unsigned int toUint(T x)
Definition: Utils.h:109
unsigned char * m_packet_buffer
Definition: OpusEncoder.h:218
OpusMSEncoder * m_encoder
Definition: OpusEncoder.h:221
Here is the call graph for this function:

◆ fillInBuffer()

unsigned int Kwave::OpusEncoder::fillInBuffer ( Kwave::MultiTrackReader src)
private

Fill the input buffer of the encoder with samples.

Parameters
srcMultiTrackReader used as source of the audio data
Returns
number of samples read

Definition at line 772 of file OpusEncoder.cpp.

References Kwave::MultiTrackSink< SINK, INITIALIZE >::at(), Kwave::SampleBuffer::available(), Kwave::MultiTrackReader::eof(), Kwave::SampleBuffer::get(), Kwave::MultiTrackSource< SOURCE, INITIALIZE >::goOn(), m_buffer, m_encoder_channels, m_encoder_input, m_extra_out, m_frame_size, and sample2float().

Referenced by encode().

773 {
774  unsigned int min_count = m_frame_size + 1; // will be used as "invalid"
775 
776  for (unsigned int t = 0; t < m_encoder_channels; ++t) {
777  Kwave::SampleBuffer *buf = m_buffer->at(t);
778  Q_ASSERT(buf);
779  if (!buf) return 0;
780 
781  unsigned int count = 0;
782  unsigned int rest = m_frame_size;
783  while (rest) {
784  float *p = m_encoder_input + t;
785 
786  // while buffer is empty and source is not at eof:
787  // trigger the start of the chain to produce some data
788  while (!buf->available() && !src.eof())
789  src.goOn();
790  const unsigned int avail = buf->available();
791  if (!avail) break; // reached EOF
792 
793  // while there is something in the current buffer
794  // and some rest is still to do
795  unsigned int len = qMin<unsigned int>(rest, avail);
796  const sample_t *s = buf->get(len);
797  Q_ASSERT(s);
798  if (!s) break;
799 
800  // fill the frame data
801  rest -= len;
802  count += len;
803  while (len--) {
804  *p = sample2float(*(s++));
805  p += m_encoder_channels;
806  }
807  }
808  if (count < min_count) min_count = count;
809  }
810 
811  // take the minimum number of samples if valid, otherwise zero (eof?)
812  unsigned int n = (min_count <= m_frame_size) ? min_count : 0;
813 
814  // if we were not able to fill a complete frame, we probably are at eof
815  // and have some space to pad with extra samples to compensate preskip
816  while ((n < m_frame_size) && m_extra_out) {
817  Q_ASSERT(src.eof());
818  for (unsigned int t = 0; t < m_encoder_channels; ++t) {
819  m_encoder_input[(n + t) * m_encoder_channels] = 0.0;
820  }
821  m_extra_out--;
822  n++;
823  }
824 
825  return n;
826 }
virtual const sample_t * get(unsigned int len)
float * m_encoder_input
Definition: OpusEncoder.h:224
virtual void goOn() Q_DECL_OVERRIDE
unsigned int m_extra_out
Definition: OpusEncoder.h:209
virtual bool eof() const
Kwave::MultiTrackSink< Kwave::SampleBuffer, true > * m_buffer
Definition: OpusEncoder.h:234
unsigned int m_encoder_channels
Definition: OpusEncoder.h:197
static float sample2float(const sample_t s)
Definition: Sample.h:65
unsigned int m_frame_size
Definition: OpusEncoder.h:206
virtual unsigned int available() const
virtual SINK * at(unsigned int track) const
qint32 sample_t
Definition: Sample.h:37
Here is the call graph for this function:
Here is the caller graph for this function:

◆ open()

bool Kwave::OpusEncoder::open ( QWidget *  widget,
const Kwave::FileInfo info,
Kwave::MultiTrackReader src 
)
virtual

parse the header of the stream and initialize the decoder

Parameters
widgeta QWidget to be used as parent for error messages
inforeference to a FileInfo to fill
srcMultiTrackReader used as source of the audio data
Returns
true if succeeded, false if failed

Implements Kwave::OggSubEncoder.

Definition at line 501 of file OpusEncoder.cpp.

References Kwave::FileInfo::bits(), Kwave::connect(), DBG, DEFAULT_COMPLEXITY, DOWNMIX_AUTO, Kwave::MessageBox::error(), m_bitrate, m_buffer, m_coding_rate, m_downmix, m_encoder, m_encoder_channels, m_extra_out, m_frame_size, m_info, m_last_queue_element, m_max_frame_bytes, m_opus_header, m_os, Kwave::opus_error(), Kwave::FileInfo::rate(), setupBitrate(), setupBitrateMode(), setupCodingRate(), setupDownMix(), setupEncoder(), and Kwave::FileInfo::tracks().

503 {
504  // get info: tracks, sample rate, bitrate(s)
505  m_info = info;
506  const unsigned int src_tracks = m_info.tracks();
507  const double sample_rate = m_info.rate();
508  int err;
509 
510  // reset everything to defaults
512  m_bitrate = -1;
513  m_coding_rate = 0;
514  m_extra_out = 0;
515  m_frame_size = 0;
516  memset(&m_opus_header, 0x00, sizeof(m_opus_header));
517  memset(&m_opus_header.map, 0xFF, sizeof(m_opus_header.map));
518  m_max_frame_bytes = 0;
519  m_last_queue_element = &src;
520 
521  // get the desired bitrate
522  if (!setupBitrate(widget, src_tracks))
523  return false;
524 
525  // determine the down mixing mode
526  // and set up the mixer if necessary
527  if (!setupDownMix(widget, src_tracks, m_bitrate))
528  return false;
529 
530  // determine the decoding sample rate
531  // and set up the rate converter if necessary
532  if (!setupCodingRate(widget, m_encoder_channels, sample_rate))
533  return false;
534 
535  // set up mapping, packet size and encoder
536  if (!setupEncoder(widget, m_encoder_channels, sample_rate))
537  return false;
538 
539  // set up bitrate mode (e.g. VBR, ABR, ...)
540  if (!setupBitrateMode(widget))
541  return false;
542 
543  // create a sample buffer at the end of the filter chain
546  );
547  Q_ASSERT(m_buffer);
548  if (!m_buffer) {
549  qWarning("cannot create sample buffer");
550  return false;
551  }
552  if (!Kwave::connect(
553  *m_last_queue_element, SIGNAL(output(Kwave::SampleArray)),
554  *m_buffer, SLOT(input(Kwave::SampleArray))) )
555  {
556  qWarning("failed to connect sample buffer");
557  return false;
558  }
559 
560  // set up the encoder complexity (ignore errors)
561  opus_int32 complexity = DEFAULT_COMPLEXITY;
562  err = opus_multistream_encoder_ctl(m_encoder,
563  OPUS_SET_COMPLEXITY(complexity));
564  if (err != OPUS_OK) {
565  qWarning("OpusEncoder: failed setting encoder complexity: '%s'",
566  DBG(Kwave::opus_error(err)));
567  }
568 
569  // set up the expected loss [percent] (ignore errors)
570  opus_int32 expect_loss = 0;
571  err = opus_multistream_encoder_ctl(m_encoder,
572  OPUS_SET_PACKET_LOSS_PERC(expect_loss));
573  if (err != OPUS_OK) {
574  qWarning("OpusEncoder: failed setting expected loss: '%s'",
575  DBG(Kwave::opus_error(err)));
576  }
577 
578 #ifdef OPUS_SET_LSB_DEPTH
579  // set up the LSB depth
580  opus_int32 bits = qBound<unsigned int>(8, m_info.bits(), 24);
581  err = opus_multistream_encoder_ctl(m_encoder, OPUS_SET_LSB_DEPTH(bits));
582  if (err != OPUS_OK) {
583  qWarning("OpusEncoder: failed setting LSB depth loss: '%s'",
584  DBG(Kwave::opus_error(err)));
585  }
586 #endif /* OPUS_SET_LSB_DEPTH */
587 
588  // get the lookahead value
589  opus_int32 lookahead;
590  err = opus_multistream_encoder_ctl(m_encoder,
591  OPUS_GET_LOOKAHEAD(&lookahead));
592  if (err != OPUS_OK) {
594  i18n("Opus encoder failed getting lookahead value: '%1'",
595  Kwave::opus_error(err)));
596  return false;
597  }
598 
599  // regardless of the rate we're coding at the ogg timestamping/skip is
600  // always timed at 48000 kBit/s
601  m_opus_header.preskip = static_cast<quint16>(
602  lookahead * (48000.0 / m_coding_rate));
603  qDebug(" OpusEncoder: preskip=%d", m_opus_header.preskip);
604 
605  /* Extra samples that need to be read to compensate for the pre-skip */
606  m_extra_out = lookahead;
607 
608 
609  // set up our packet->stream encoder
610  // pick a random serial number; that way we can more likely build
611  // chained streams just by concatenation
612  qsrand(QTime::currentTime().msec() ^ qrand());
613  ogg_stream_init(&m_os, qrand());
614 
615  return true;
616 }
Kwave::opus_header_t m_opus_header
Definition: OpusEncoder.h:212
double rate() const
Definition: FileInfo.cpp:415
Kwave::FileInfo m_info
Definition: OpusEncoder.h:169
bool setupBitrate(QWidget *widget, unsigned int tracks)
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
unsigned int m_extra_out
Definition: OpusEncoder.h:209
Kwave::MultiTrackSink< Kwave::SampleBuffer, true > * m_buffer
Definition: OpusEncoder.h:234
unsigned int m_encoder_channels
Definition: OpusEncoder.h:197
static int error(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:126
unsigned int m_max_frame_bytes
Definition: OpusEncoder.h:215
bool setupEncoder(QWidget *widget, unsigned int tracks, double rate)
Kwave::StreamObject * m_last_queue_element
Definition: OpusEncoder.h:231
QString opus_error(int err)
Definition: OpusCommon.cpp:45
unsigned int tracks() const
Definition: FileInfo.cpp:445
bool setupCodingRate(QWidget *widget, unsigned int tracks, double rate)
unsigned int m_frame_size
Definition: OpusEncoder.h:206
ogg_stream_state m_os
Definition: OpusEncoder.h:172
#define DEFAULT_COMPLEXITY
Definition: OpusEncoder.cpp:93
#define DBG(qs)
Definition: String.h:55
bool setupDownMix(QWidget *widget, unsigned int tracks, int bitrate)
OpusMSEncoder * m_encoder
Definition: OpusEncoder.h:221
unsigned int bits() const
Definition: FileInfo.cpp:430
bool setupBitrateMode(QWidget *widget)
enum Kwave::OpusEncoder::@12 m_downmix
Here is the call graph for this function:

◆ setupBitrate()

bool Kwave::OpusEncoder::setupBitrate ( QWidget *  widget,
unsigned int  tracks 
)
private

determine the bitrate to use for encoding

Parameters
widgeta QWidget to be used as parent for error messages
tracksnumber of tracks
Returns
true if succeeded or false if failed/canceled

Definition at line 195 of file OpusEncoder.cpp.

References _, BITRATE_MAX, BITRATE_MIN, Kwave::FileInfo::contains(), Kwave::FileInfo::get(), Kwave::INF_BITRATE_LOWER, Kwave::INF_BITRATE_NOMINAL, Kwave::INF_BITRATE_UPPER, m_bitrate, m_info, Kwave::toInt(), and Kwave::MessageBox::warningContinueCancel().

Referenced by open().

196 {
197  int bitrate_nominal = m_info.contains(Kwave::INF_BITRATE_NOMINAL) ?
198  QVariant(m_info.get(Kwave::INF_BITRATE_NOMINAL)).toInt() : -1;
199  int bitrate_lower = m_info.contains(Kwave::INF_BITRATE_LOWER) ?
200  QVariant(m_info.get(Kwave::INF_BITRATE_LOWER)).toInt() : -1;
201  int bitrate_upper = m_info.contains(Kwave::INF_BITRATE_UPPER) ?
202  QVariant(m_info.get(Kwave::INF_BITRATE_UPPER)).toInt() : -1;
203 
204  // prefer bitrates in this order:
205  // nominal -> upper -> lower -> "auto" (-1)
206  int bitrate = -1;
207  if (bitrate_nominal > 0) bitrate = bitrate_nominal;
208  else if (bitrate_upper > 0) bitrate = bitrate_upper;
209  else if (bitrate_lower > 0) bitrate = bitrate_lower;
210 
211  if ((bitrate > 0) && ((bitrate > (BITRATE_MAX * Kwave::toInt(tracks)))
212  || (bitrate < BITRATE_MIN)))
213  {
214  int bitrate_new =
215  qBound<int>(BITRATE_MIN, bitrate, BITRATE_MAX * tracks);
216 
218  widget,
219  i18nc("%1=original bitrate, %2=new/limited bitrate",
220  "Bitrate %1 kBit/sec is out of range, "
221  "limited to %2 kBit/sec",
222  bitrate / 1000,
223  bitrate_new / 1000),
224  QString(), QString(), QString(),
225  _("opus_bitrate_limit")) != KMessageBox::Continue)
226  {
227  return false;
228  }
229  }
230 
231  if (bitrate > 0)
232  qDebug(" OpusEncoder: bitrate %d bits/sec (configured)", bitrate);
233  m_bitrate = bitrate;
234  return true;
235 }
bool contains(const FileProperty property) const
Definition: FileInfo.cpp:354
Kwave::FileInfo m_info
Definition: OpusEncoder.h:169
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
#define BITRATE_MAX
Definition: OpusEncoder.cpp:84
int toInt(T x)
Definition: Utils.h:127
static int warningContinueCancel(QWidget *widget, QString message, QString caption=QString(), const QString buttonContinue=QString(), const QString buttonCancel=QString(), const QString &dontAskAgainName=QString())
Definition: MessageBox.cpp:115
#define _(m)
Definition: memcpy.c:66
#define BITRATE_MIN
Definition: OpusEncoder.cpp:81
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setupBitrateMode()

bool Kwave::OpusEncoder::setupBitrateMode ( QWidget *  widget)
private

set up the bitrate mode, e.g. VBR, CBR etc

Parameters
widgeta QWidget to be used as parent for error messages
Returns
true if succeeded or false if failed/canceled

Definition at line 452 of file OpusEncoder.cpp.

References Kwave::BITRATE_MODE_CBR_HARD, Kwave::MessageBox::error(), Kwave::FileInfo::get(), Kwave::INF_BITRATE_MODE, m_bitrate, m_encoder, m_info, m_opus_header, and Kwave::opus_error().

Referenced by open().

453 {
454  const bool with_cvbr = false;
455  int err;
456 
457  // determine a reasonable bitrate in case we still use "autodetect"
458  if (m_bitrate < 0) {
459  m_bitrate = (64000 * m_opus_header.streams) +
460  (32000 * m_opus_header.coupled);
461  m_bitrate = qBound<int>(500, m_bitrate, 256000);
462  qDebug(" OpusEncoder: bitrate %d bits/sec (auto)", m_bitrate);
463  }
464 
465  err = opus_multistream_encoder_ctl(m_encoder, OPUS_SET_BITRATE(
466  static_cast<opus_int32>(m_bitrate)));
467  if (err != OPUS_OK) {
469  i18n("Opus encoder failed setting bitrate: '%1'",
470  Kwave::opus_error(err)));
471  return false;
472  }
473 
474  int bitrate_mode = m_info.get(INF_BITRATE_MODE).toInt();
475  bool with_hard_cbr = (bitrate_mode == BITRATE_MODE_CBR_HARD);
476 
477  err = opus_multistream_encoder_ctl(m_encoder, OPUS_SET_VBR(
478  static_cast<opus_int32>(with_hard_cbr ? 0 : 1)));
479  if (err != OPUS_OK) {
481  i18n("Opus encoder failed configuring VBR mode: '%1'",
482  Kwave::opus_error(err)));
483  return false;
484  }
485 
486  if (!with_hard_cbr ) {
487  err = opus_multistream_encoder_ctl(m_encoder, OPUS_SET_VBR_CONSTRAINT(
488  static_cast<opus_int32>(with_cvbr ? 1 : 0)));
489  if (err != OPUS_OK) {
491  i18n("Opus encoder failed configuring VBR constraint: '%1'",
492  Kwave::opus_error(err)));
493  return false;
494  }
495  }
496 
497  return true;
498 }
Kwave::opus_header_t m_opus_header
Definition: OpusEncoder.h:212
Kwave::FileInfo m_info
Definition: OpusEncoder.h:169
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
static int error(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:126
QString opus_error(int err)
Definition: OpusCommon.cpp:45
OpusMSEncoder * m_encoder
Definition: OpusEncoder.h:221
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setupCodingRate()

bool Kwave::OpusEncoder::setupCodingRate ( QWidget *  widget,
unsigned int  tracks,
double  rate 
)
private

determine the sample rate to use for encoding

Parameters
widgeta QWidget to be used as parent for error messages
tracksnumber of tracks
ratesample rate of the original in samples/sec
Returns
true if succeeded or false if failed/canceled

Definition at line 238 of file OpusEncoder.cpp.

References Kwave::connect(), m_coding_rate, m_last_queue_element, m_rate_converter, Kwave::opus_next_sample_rate(), SAMPLE_RATE_MAX, SAMPLE_RATE_MIN, Kwave::StreamObject::setAttribute(), Kwave::MessageBox::sorry(), and Kwave::toInt().

Referenced by open().

240 {
241  Q_UNUSED(widget);
242 
243  Q_ASSERT(!m_rate_converter);
244 
245  int rate_orig = Kwave::toInt(rate);
246  int rate_supp = Kwave::opus_next_sample_rate(rate_orig);
247 
248  m_coding_rate = rate_supp;
249 
250  if (rate_orig == rate_supp) {
251  qDebug(" OpusEncoder: using sample rate %d", rate_orig);
252  return true; // no conversion needed :-)
253  }
254 
255  double rate_from = static_cast<double>(rate_orig);
256  double rate_to = static_cast<double>(rate_supp);
257  double ratio = rate_to / rate_from;
258 
259  qDebug(" OpusEncoder: converting sample rate: %d -> %d",
260  rate_orig, rate_supp);
261 
262  // range check: conversion ration must be between 1/256 and 256
263  if ((ratio < (1.0 / 256.0)) || (ratio > 256.0)) {
264  int lowest = qMin<int>(SAMPLE_RATE_MIN,
265  Kwave::toInt(ceil( rate_to / 256.0)));
266  int highest = qMax<int>(Kwave::toInt(floor(rate_to * 256.0)),
269  widget,
270  i18nc("%1=requested sample rate, "
271  "%2=lowest supported, %3=highest supported",
272  "Sample rate %1 samples/sec is out of range,\n"
273  "supported are %2 ... %3 samples/sec.",
274  rate_supp, lowest, highest),
275  QString()
276  );
277  return false;
278  }
279 
280  // create a new rate converter
283  Q_ASSERT(m_rate_converter);
284  if (!m_rate_converter)
285  return false;
286 
288  SLOT(setRatio(QVariant)),
289  QVariant(ratio)
290  );
291 
292  // connect the rate converter to the end of the current preprocessing
293  // queue/ (normally this is either the original sample source or
294  // a channel mixer)
295  if (!Kwave::connect(
296  *m_last_queue_element, SIGNAL(output(Kwave::SampleArray)),
297  *m_rate_converter, SLOT(input(Kwave::SampleArray))))
298  {
299  qWarning("connecting the rate converter failed");
300  return false;
301  }
303 
304  return true;
305 }
int opus_next_sample_rate(int rate)
Definition: OpusCommon.cpp:30
Kwave::StreamObject * m_rate_converter
Definition: OpusEncoder.h:203
static int sorry(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:85
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
int toInt(T x)
Definition: Utils.h:127
Kwave::StreamObject * m_last_queue_element
Definition: OpusEncoder.h:231
#define SAMPLE_RATE_MIN
Definition: OpusEncoder.cpp:87
#define SAMPLE_RATE_MAX
Definition: OpusEncoder.cpp:90
void setAttribute(const char *attribute, const QVariant &value)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setupDownMix()

bool Kwave::OpusEncoder::setupDownMix ( QWidget *  widget,
unsigned int  tracks,
int  bitrate 
)
private

set up the downmixing mode

Parameters
widgeta QWidget to be used as parent for error messages
tracksnumber of tracks
bitratein bits/sec or -1 for "auto"
Returns
true if succeeded or false if failed/canceled

Definition at line 126 of file OpusEncoder.cpp.

References _, Kwave::connect(), DOWNMIX_AUTO, DOWNMIX_MONO, DOWNMIX_OFF, DOWNMIX_STEREO, Kwave::ChannelMixer::init(), m_channel_mixer, m_downmix, m_encoder_channels, m_last_queue_element, Kwave::toInt(), and Kwave::MessageBox::warningContinueCancel().

Referenced by open().

128 {
129  // get "downmix" setting, default is "auto"
130  m_downmix = DOWNMIX_AUTO; // currently not user configurable
131 
132  if ((m_downmix == DOWNMIX_AUTO) &&
133  (bitrate > 0) && (bitrate < (32000 * Kwave::toInt(tracks))))
134  {
135  if (tracks > 8) {
136  // downmix from more than 8 channels to mono
138  widget,
139  i18n("Surround bitrate would be less than 32kBit/sec per "
140  "channel, this file should be mixed down to mono."),
141  QString(), QString(), QString(),
142  _("opus_accept_down_mix_on_export")) != KMessageBox::Continue)
143  {
144  return false;
145  }
147  } else if (tracks > 2) {
148  // downmix from more than stereo to stereo
150  widget,
151  i18n("Surround bitrate would be less than 32kBit/sec per "
152  "channel, this file should be mixed down to stereo."),
153  QString(), QString(), QString(),
154  _("opus_accept_down_mix_on_export")) != KMessageBox::Continue)
155  {
156  return false;
157  }
159  }
160  }
161  if (m_downmix == DOWNMIX_AUTO) // if still "auto"
162  m_downmix = DOWNMIX_OFF; // then switch it off
163 
164  switch (m_downmix) {
165  case DOWNMIX_MONO: m_encoder_channels = 1; break;
166  case DOWNMIX_STEREO: m_encoder_channels = 2; break;
167  default: m_encoder_channels = tracks; break;
168  }
169 
170  if (m_encoder_channels != tracks) {
171  // create a channel mixer
173  Q_ASSERT(m_channel_mixer);
174  if (!m_channel_mixer || !m_channel_mixer->init()) {
175  qWarning("creating channel mixer failed");
176  return false;
177  }
178 
179  // connect it to the end of the current preprocessing queue
180  // (normally this is the original sample source)
181  if (!Kwave::connect(
182  *m_last_queue_element, SIGNAL(output(Kwave::SampleArray)),
183  *m_channel_mixer, SLOT(input(Kwave::SampleArray))))
184  {
185  qWarning("connecting the channel mixer failed");
186  return false;
187  }
189  }
190 
191  return true;
192 }
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
virtual bool init()
unsigned int m_encoder_channels
Definition: OpusEncoder.h:197
int toInt(T x)
Definition: Utils.h:127
Kwave::ChannelMixer * m_channel_mixer
Definition: OpusEncoder.h:200
Kwave::StreamObject * m_last_queue_element
Definition: OpusEncoder.h:231
static int warningContinueCancel(QWidget *widget, QString message, QString caption=QString(), const QString buttonContinue=QString(), const QString buttonCancel=QString(), const QString &dontAskAgainName=QString())
Definition: MessageBox.cpp:115
#define _(m)
Definition: memcpy.c:66
enum Kwave::OpusEncoder::@12 m_downmix
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setupEncoder()

bool Kwave::OpusEncoder::setupEncoder ( QWidget *  widget,
unsigned int  tracks,
double  rate 
)
private

set up the encoder, including packet size and channel mapping

Parameters
widgeta QWidget to be used as parent for error messages
tracksnumber of tracks
ratesample rate of the original in samples/sec
Returns
true if succeeded or false if failed/canceled

Definition at line 308 of file OpusEncoder.cpp.

References Kwave::FileInfo::contains(), Kwave::MessageBox::error(), Kwave::FileInfo::get(), Kwave::INF_OPUS_FRAME_LEN, m_coding_rate, m_encoder, m_encoder_input, m_frame_size, m_info, m_max_frame_bytes, m_opus_header, m_packet_buffer, Kwave::opus_error(), and Kwave::toUint().

Referenced by open().

310 {
311  // get the frame size in ms if present,
312  // otherwise fall back to the default of 20ms
313  // (supported values are 2.5, 5, 10, 20, 40, or 60 ms)
314  qreal ms_per_frame = 20.0; // default is 20ms
316  double len = m_info.get(INF_OPUS_FRAME_LEN).toDouble();
317  if (len >= 60)
318  ms_per_frame = 60.0;
319  else if (len >= 40)
320  ms_per_frame = 40.0;
321  else if (len >= 20)
322  ms_per_frame = 20.0;
323  else if (len >= 5)
324  ms_per_frame = 5;
325  else
326  ms_per_frame = 2.5;
327  qDebug(" OpusEncoder: %0.1f ms/frame", ms_per_frame);
328  } else {
329  ms_per_frame = 20.0; // <- default
330  qDebug(" OpusEncoder: %0.1f ms/frame (default)", ms_per_frame);
331  }
332 
333  // calculate the frame size in samples from the frame duration in ms
334  // = frame_length [ms] * bitrate [bits/sec] / 1000 [ms/sec]
336  (ms_per_frame * m_coding_rate) / 1000);
337 
338  if (tracks > 255) {
339  qWarning("too many tracks: %u, supported: 255", tracks);
340  return false; // more than 255 tracks are not supported
341  }
342 
343  // fill out all header fields
344  m_opus_header.channels = static_cast<quint8>(tracks);
345  m_opus_header.preskip = 0;
346  m_opus_header.sample_rate = static_cast<quint32>(rate);
347  m_opus_header.gain = 0;
348  m_opus_header.channel_mapping = 255;
349  m_opus_header.streams = static_cast<quint8>(tracks);
350  m_opus_header.coupled = 0;
351 
352  // determine channel mapping and coupling
353  quint8 force_narrow = 0x00;
354  if (tracks <= 8) {
355  /* apply a mapping as done in opusenc.c from opus-tools-0.1.5 */
356  static const quint8 opusenc_streams[8][10]= {
357  /* Coupled, NB_bitmap, mapping...*/
358  /* 1 */ {0, 0, 0 },
359  /* 2 */ {1, 0, 0, 1 },
360  /* 3 */ {1, 0, 0, 2, 1 },
361  /* 4 */ {2, 0, 0, 1, 2, 3 },
362  /* 5 */ {2, 0, 0, 4, 1, 2, 3 },
363  /* 6 */ {2, 1 << 3, 0, 4, 1, 2, 3, 5 },
364  /* 7 */ {2, 1 << 4, 0, 4, 1, 2, 3, 5, 6 },
365  /* 8 */ {3, 1 << 4, 0, 6, 1, 2, 3, 4, 5, 7 }
366  };
367  for (unsigned int i = 0; i < tracks; i++)
368  m_opus_header.map[i] = opusenc_streams[tracks - 1][i + 2];
369  force_narrow = opusenc_streams[tracks - 1][1];
370  m_opus_header.coupled = opusenc_streams[tracks - 1][0];
371  m_opus_header.streams = static_cast<quint8>(
372  tracks - m_opus_header.coupled);
373  m_opus_header.channel_mapping = (m_opus_header.streams > 1);
374 
375  qDebug(" OpusEncoder: %d stream(s) / %d coupled (mapping=%d)",
376  m_opus_header.streams, m_opus_header.coupled,
377  m_opus_header.channel_mapping);
378  } else {
379  /* map all channels 1:1 */
380  for (quint8 i = 0; i < m_opus_header.channels; ++i)
381  m_opus_header.map[i] = i;
382  qDebug(" OpusEncoder: mapping channels 1:1");
383  }
384 
385  // allocate a packet buffer
386  m_max_frame_bytes = ((1275 * 3) + 7) * m_opus_header.streams;
387  qDebug(" OpusEncoder: max frame size %u bytes", m_max_frame_bytes);
388  Q_ASSERT(!m_packet_buffer);
389  m_packet_buffer = static_cast<unsigned char *>(malloc(m_max_frame_bytes));
390  if (!m_packet_buffer) {
391  Kwave::MessageBox::error(widget, i18n("Out of memory"));
392  return false;
393  }
394 
395  // initialize the Opus encoder:
396  // frame sizes < 10ms can only use the MDCT modes,
397  // so we switch on RESTRICTED_LOWDELAY to save the extra 2.5ms of codec
398  // lookahead when we'll be using only small frames
399 
400  int err = OPUS_ALLOC_FAIL;
401  Q_ASSERT(!m_encoder);
402  m_encoder = opus_multistream_encoder_create(
404  tracks,
405  m_opus_header.streams,
406  m_opus_header.coupled,
407  m_opus_header.map,
408  (ms_per_frame < 10.0) ? OPUS_APPLICATION_RESTRICTED_LOWDELAY :
409  OPUS_APPLICATION_AUDIO,
410  &err
411  );
412  if (err != OPUS_OK) {
414  i18n("Opus encoder failed"));
415  return false;
416  }
417 
418  if (force_narrow) {
419  for (unsigned int i = 0; i < m_opus_header.streams; i++ ) {
420  if (force_narrow & (1 << i)) {
421  ::OpusEncoder *oe = Q_NULLPTR;
422 
423  opus_multistream_encoder_ctl(
424  m_encoder,
425  OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, i, &oe
426  );
427 
428  int err_ctl = opus_encoder_ctl(oe,
429  OPUS_SET_MAX_BANDWIDTH_REQUEST, OPUS_BANDWIDTH_NARROWBAND);
430 
431  if (err_ctl != OPUS_OK) {
433  i18n("Opus encoder failed"));
434  return false;
435  }
436  }
437  }
438  }
439 
440  // allocate a buffer to be used as input of the encoder
441  m_encoder_input = static_cast<float *>(
442  malloc(sizeof(float) * m_frame_size * tracks));
443  if (!m_encoder_input) {
444  Kwave::MessageBox::error(widget, i18n("Out of memory"));
445  return false;
446  }
447 
448  return true;
449 }
Kwave::opus_header_t m_opus_header
Definition: OpusEncoder.h:212
bool contains(const FileProperty property) const
Definition: FileInfo.cpp:354
Kwave::FileInfo m_info
Definition: OpusEncoder.h:169
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
float * m_encoder_input
Definition: OpusEncoder.h:224
static int error(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:126
unsigned int m_max_frame_bytes
Definition: OpusEncoder.h:215
QString opus_error(int err)
Definition: OpusCommon.cpp:45
unsigned int m_frame_size
Definition: OpusEncoder.h:206
unsigned int toUint(T x)
Definition: Utils.h:109
unsigned char * m_packet_buffer
Definition: OpusEncoder.h:218
OpusMSEncoder * m_encoder
Definition: OpusEncoder.h:221
Here is the call graph for this function:
Here is the caller graph for this function:

◆ writeHeader()

bool Kwave::OpusEncoder::writeHeader ( QIODevice &  dst)
virtual

write the header information

Parameters
dsta QIODevice that receives the raw data
Returns
true if succeeded, false if failed

Implements Kwave::OggSubEncoder.

Definition at line 733 of file OpusEncoder.cpp.

References writeOpusHeader(), and writeOpusTags().

734 {
735  if (!writeOpusHeader(dst))
736  return false;
737 
738  if (!writeOpusTags(dst))
739  return false;
740 
741  return true;
742 }
bool writeOpusTags(QIODevice &dst)
bool writeOpusHeader(QIODevice &dst)
Here is the call graph for this function:

◆ writeOggPage()

bool Kwave::OpusEncoder::writeOggPage ( QIODevice &  dst)
private

Write the current ogg page to the destination IO device

Parameters
dsta QIODevice that receives the raw data
Returns
true if succeeded or false if failed/canceled

Definition at line 745 of file OpusEncoder.cpp.

References m_og.

Referenced by encode(), and writeOpusTags().

746 {
747  qint64 n;
748 
749  n = dst.write(reinterpret_cast<char *>(m_og.header), m_og.header_len);
750  if (n != m_og.header_len) {
751  qWarning("OpusEncoder: I/O error writing header, len=%u, written=%u",
752  static_cast<unsigned int>(n),
753  static_cast<unsigned int>(m_og.header_len));
754  return false; // write error ?
755  }
756 
757  n = dst.write(reinterpret_cast<char *>(m_og.body), m_og.body_len);
758  if (n != m_og.body_len) {
759  qWarning("OpusEncoder: I/O error writing body, len=%u, written=%u",
760  static_cast<unsigned int>(n),
761  static_cast<unsigned int>(m_og.body_len));
762  return false; // write error ?
763  }
764 
765  // update the progress bar
766  QApplication::processEvents();
767 
768  return true;
769 }
Here is the caller graph for this function:

◆ writeOpusHeader()

bool Kwave::OpusEncoder::writeOpusHeader ( QIODevice &  dst)
private

write the Opus header into the Ogg stream

Parameters
dsta QIODevice that receives the raw data
Returns
true if succeeded or false if failed/canceled

Definition at line 626 of file OpusEncoder.cpp.

References m_og, m_op, m_opus_header, and m_os.

Referenced by writeHeader().

627 {
628  Kwave::opus_header_t header;
629  unsigned int len;
630 
631  // create an Opus header, using correct byte order
632  memset(&header, 0x00, sizeof(header));
633  memset(&header.map, 0xFF, sizeof(header.map));
634 
635  memcpy(&(header.magic[0]), "OpusHead", 8);
636  header.version = 1;
637  header.channels = m_opus_header.channels;
638  header.preskip = qToLittleEndian<quint16>(m_opus_header.preskip);
639  header.sample_rate = qToLittleEndian<quint32>(m_opus_header.sample_rate);
640  header.gain = qToLittleEndian<quint16>(m_opus_header.gain);
641  header.channel_mapping = m_opus_header.channel_mapping;
642  len = 19; // bytes so far
643  if (m_opus_header.channel_mapping) {
644  header.streams = m_opus_header.streams;
645  header.coupled = m_opus_header.coupled;
646  len += 2;
647 
648  for (quint8 i = 0; i < m_opus_header.channels; ++i)
649  header.map[i] = m_opus_header.map[i];
650  len += m_opus_header.channels;
651  }
652 
653  // write the header into the ogg stream
654  m_op.packet = reinterpret_cast<unsigned char *>(&header);
655  m_op.bytes = len;
656  m_op.b_o_s = 1;
657  m_op.e_o_s = 0;
658  m_op.granulepos = 0;
659  m_op.packetno = 0;
660  ogg_stream_packetin(&m_os, &m_op);
661 
662  while (ogg_stream_flush(&m_os, &m_og)) {
663  dst.write(reinterpret_cast<char *>(m_og.header),
664  m_og.header_len);
665  dst.write(reinterpret_cast<char *>(m_og.body),
666  m_og.body_len);
667  }
668 
669  return true;
670 }
Kwave::opus_header_t m_opus_header
Definition: OpusEncoder.h:212
ogg_stream_state m_os
Definition: OpusEncoder.h:172
Here is the caller graph for this function:

◆ writeOpusTags()

bool Kwave::OpusEncoder::writeOpusTags ( QIODevice &  dst)
private

write the Opus tags into the Ogg stream

Parameters
dsta QIODevice that receives the raw data
Returns
true if succeeded or false if failed/canceled

Definition at line 673 of file OpusEncoder.cpp.

References _, _writeInt(), Kwave::FileInfo::contains(), Kwave::FileInfo::get(), Kwave::INF_SOFTWARE, m_comments_map, m_info, m_og, m_op, m_os, and writeOggPage().

Referenced by writeHeader().

674 {
675  QBuffer buffer;
676 
677  buffer.open(QBuffer::ReadWrite);
678 
679  // let the header start with the magic string "OpusTags"
680  buffer.write("OpusTags", 8);
681 
682  // write the vendor string == name + version of the encoder library
683  const char *opus_version = opus_get_version_string();
684  quint32 len = quint32(strlen(opus_version));
685  _writeInt(buffer, len);
686  buffer.write(opus_version, len);
687 
688  // iterate over all known properties and collect them in a list
689  QList<QByteArray> tags;
690  len = 0;
691  foreach (const QString &key, m_comments_map.keys()) {
692  Kwave::FileProperty property = m_comments_map[key];
693  if (!m_info.contains(property)) continue; // skip if not present
694 
695  // convert the value into a byte array, UTF-8 encoded
696  QString str = key + _("=") + m_info.get(property).toString();
697  QByteArray v = str.toUtf8();
698 
699  // make sure that the "ENCODER" tag is at the start of the list
700  if ((property == INF_SOFTWARE) && (!tags.isEmpty()))
701  tags.prepend(v);
702  else
703  tags.append(v);
704 
705  len += (4 + v.size()); // sum up the data length
706  }
707 
708  // write the number of user tags
709  _writeInt(buffer, tags.count());
710 
711  // serialize the tags into the buffer
712  foreach (const QByteArray &tag, tags) {
713  _writeInt(buffer, tag.size());
714  buffer.write(tag);
715  }
716 
717  m_op.packet = reinterpret_cast<unsigned char *>(buffer.buffer().data());
718  m_op.bytes = static_cast<long int>(buffer.size());
719  m_op.b_o_s = 0;
720  m_op.e_o_s = 0;
721  m_op.granulepos = 0;
722  m_op.packetno = 1;
723  ogg_stream_packetin(&m_os, &m_op);
724 
725  while (ogg_stream_flush(&m_os, &m_og)) {
726  if (!writeOggPage(dst)) return false;
727  }
728 
729  return true;
730 }
bool contains(const FileProperty property) const
Definition: FileInfo.cpp:354
Kwave::FileInfo m_info
Definition: OpusEncoder.h:169
static void _writeInt(QBuffer &buffer, quint32 value)
bool writeOggPage(QIODevice &dst)
Kwave::VorbisCommentMap m_comments_map
Definition: OpusEncoder.h:166
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
#define _(m)
Definition: memcpy.c:66
ogg_stream_state m_os
Definition: OpusEncoder.h:172
FileProperty
Definition: FileInfo.h:45
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_bitrate

int Kwave::OpusEncoder::m_bitrate
private

bitrate in bits/sec

Definition at line 191 of file OpusEncoder.h.

Referenced by open(), setupBitrate(), and setupBitrateMode().

◆ m_buffer

Kwave::MultiTrackSink<Kwave::SampleBuffer, true>* Kwave::OpusEncoder::m_buffer
private

multi track buffer, for blockwise reading from the source device

Definition at line 234 of file OpusEncoder.h.

Referenced by close(), fillInBuffer(), and open().

◆ m_channel_mixer

Kwave::ChannelMixer* Kwave::OpusEncoder::m_channel_mixer
private

channel mixer (if downmixing is required)

Definition at line 200 of file OpusEncoder.h.

Referenced by close(), and setupDownMix().

◆ m_coding_rate

int Kwave::OpusEncoder::m_coding_rate
private

encoding sample rate in bits/sec

Definition at line 194 of file OpusEncoder.h.

Referenced by encode(), open(), setupCodingRate(), and setupEncoder().

◆ m_comments_map

Kwave::VorbisCommentMap Kwave::OpusEncoder::m_comments_map
private

map for translating Opus comments to Kwave FileInfo

Definition at line 166 of file OpusEncoder.h.

Referenced by writeOpusTags().

◆ m_downmix

enum { ... } Kwave::OpusEncoder::m_downmix

downmix mode: off, automatic, mono or stereo

Referenced by open(), and setupDownMix().

◆ m_encoder

OpusMSEncoder* Kwave::OpusEncoder::m_encoder
private

the Opus multistream encoder

Definition at line 221 of file OpusEncoder.h.

Referenced by close(), encode(), open(), setupBitrateMode(), and setupEncoder().

◆ m_encoder_channels

unsigned int Kwave::OpusEncoder::m_encoder_channels
private

number of tracks used for encoding, after downmixing

Definition at line 197 of file OpusEncoder.h.

Referenced by encode(), fillInBuffer(), open(), and setupDownMix().

◆ m_encoder_input

float* Kwave::OpusEncoder::m_encoder_input
private

input buffer of the encoder

Definition at line 224 of file OpusEncoder.h.

Referenced by close(), encode(), fillInBuffer(), and setupEncoder().

◆ m_extra_out

unsigned int Kwave::OpusEncoder::m_extra_out
private

number of samples to pad at the end to compensate preskip

Definition at line 209 of file OpusEncoder.h.

Referenced by fillInBuffer(), and open().

◆ m_frame_size

unsigned int Kwave::OpusEncoder::m_frame_size
private

frame size in samples

Definition at line 206 of file OpusEncoder.h.

Referenced by encode(), fillInBuffer(), open(), and setupEncoder().

◆ m_info

Kwave::FileInfo Kwave::OpusEncoder::m_info
private

file info, set in open(...)

Definition at line 169 of file OpusEncoder.h.

Referenced by encode(), open(), setupBitrate(), setupBitrateMode(), setupEncoder(), and writeOpusTags().

◆ m_last_queue_element

Kwave::StreamObject* Kwave::OpusEncoder::m_last_queue_element
private

end of the queue that possibly consists of a channel mixer (in case of downmixing), a rate converter (if needed) and a buffer (if one of the two objects mentioned before is present).

Definition at line 231 of file OpusEncoder.h.

Referenced by close(), open(), setupCodingRate(), and setupDownMix().

◆ m_max_frame_bytes

unsigned int Kwave::OpusEncoder::m_max_frame_bytes
private

maximum number of bytes per frame

Definition at line 215 of file OpusEncoder.h.

Referenced by encode(), open(), and setupEncoder().

◆ m_og

ogg_page Kwave::OpusEncoder::m_og
private

one Ogg bitstream page. Opus packets are inside

Definition at line 175 of file OpusEncoder.h.

Referenced by encode(), writeOggPage(), writeOpusHeader(), and writeOpusTags().

◆ m_op

ogg_packet Kwave::OpusEncoder::m_op
private

one raw packet of data for decode

Definition at line 178 of file OpusEncoder.h.

Referenced by encode(), writeOpusHeader(), and writeOpusTags().

◆ m_opus_header

Kwave::opus_header_t Kwave::OpusEncoder::m_opus_header
private

Opus header, including channel map

Definition at line 212 of file OpusEncoder.h.

Referenced by encode(), open(), OpusEncoder(), setupBitrateMode(), setupEncoder(), and writeOpusHeader().

◆ m_os

ogg_stream_state Kwave::OpusEncoder::m_os
private

take physical pages, weld into a logical stream of packets

Definition at line 172 of file OpusEncoder.h.

Referenced by close(), encode(), open(), writeOpusHeader(), and writeOpusTags().

◆ m_packet_buffer

unsigned char* Kwave::OpusEncoder::m_packet_buffer
private

buffer for one packet

Definition at line 218 of file OpusEncoder.h.

Referenced by close(), encode(), and setupEncoder().

◆ m_rate_converter

Kwave::StreamObject* Kwave::OpusEncoder::m_rate_converter
private

sample rate converter (if needed)

Definition at line 203 of file OpusEncoder.h.

Referenced by close(), and setupCodingRate().


The documentation for this class was generated from the following files: