54 #include <opus/opus_defines.h> 56 #include <QApplication> 65 #include <KLocalizedString> 81 #define BITRATE_MIN 500 84 #define BITRATE_MAX 256000 87 #define SAMPLE_RATE_MIN 1000 90 #define SAMPLE_RATE_MAX 512000 93 #define DEFAULT_COMPLEXITY 10 99 m_downmix(DOWNMIX_AUTO),
102 m_encoder_channels(0),
103 m_channel_mixer(Q_NULLPTR),
104 m_rate_converter(Q_NULLPTR),
108 m_max_frame_bytes(0),
109 m_packet_buffer(Q_NULLPTR),
110 m_encoder(Q_NULLPTR),
111 m_encoder_input(Q_NULLPTR),
112 m_last_queue_element(Q_NULLPTR),
133 (bitrate > 0) && (bitrate < (32000 *
Kwave::toInt(tracks))))
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)
147 }
else if (tracks > 2) {
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)
175 qWarning(
"creating channel mixer failed");
185 qWarning(
"connecting the channel mixer failed");
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;
219 i18nc(
"%1=original bitrate, %2=new/limited bitrate",
220 "Bitrate %1 kBit/sec is out of range, " 221 "limited to %2 kBit/sec",
224 QString(), QString(), QString(),
225 _(
"opus_bitrate_limit")) != KMessageBox::Continue)
232 qDebug(
" OpusEncoder: bitrate %d bits/sec (configured)", bitrate);
239 unsigned int tracks,
double rate)
250 if (rate_orig == rate_supp) {
251 qDebug(
" OpusEncoder: using sample rate %d", rate_orig);
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;
259 qDebug(
" OpusEncoder: converting sample rate: %d -> %d",
260 rate_orig, rate_supp);
263 if ((ratio < (1.0 / 256.0)) || (ratio > 256.0)) {
266 int highest = qMax<int>(
Kwave::toInt(floor(rate_to * 256.0)),
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),
288 SLOT(setRatio(QVariant)),
299 qWarning(
"connecting the rate converter failed");
314 qreal ms_per_frame = 20.0;
327 qDebug(
" OpusEncoder: %0.1f ms/frame", ms_per_frame);
330 qDebug(
" OpusEncoder: %0.1f ms/frame (default)", ms_per_frame);
339 qWarning(
"too many tracks: %u, supported: 255", tracks);
353 quint8 force_narrow = 0x00;
356 static const quint8 opusenc_streams[8][10]= {
362 {2, 0, 0, 4, 1, 2, 3 },
363 {2, 1 << 3, 0, 4, 1, 2, 3, 5 },
364 {2, 1 << 4, 0, 4, 1, 2, 3, 5, 6 },
365 {3, 1 << 4, 0, 6, 1, 2, 3, 4, 5, 7 }
367 for (
unsigned int i = 0; i < tracks; i++)
369 force_narrow = opusenc_streams[tracks - 1][1];
375 qDebug(
" OpusEncoder: %d stream(s) / %d coupled (mapping=%d)",
382 qDebug(
" OpusEncoder: mapping channels 1:1");
400 int err = OPUS_ALLOC_FAIL;
402 m_encoder = opus_multistream_encoder_create(
408 (ms_per_frame < 10.0) ? OPUS_APPLICATION_RESTRICTED_LOWDELAY :
409 OPUS_APPLICATION_AUDIO,
412 if (err != OPUS_OK) {
414 i18n(
"Opus encoder failed"));
420 if (force_narrow & (1 << i)) {
423 opus_multistream_encoder_ctl(
425 OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, i, &oe
428 int err_ctl = opus_encoder_ctl(oe,
429 OPUS_SET_MAX_BANDWIDTH_REQUEST, OPUS_BANDWIDTH_NARROWBAND);
431 if (err_ctl != OPUS_OK) {
433 i18n(
"Opus encoder failed"));
454 const bool with_cvbr =
false;
462 qDebug(
" OpusEncoder: bitrate %d bits/sec (auto)", m_bitrate);
465 err = opus_multistream_encoder_ctl(
m_encoder, OPUS_SET_BITRATE(
467 if (err != OPUS_OK) {
469 i18n(
"Opus encoder failed setting bitrate: '%1'",
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'",
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'",
549 qWarning(
"cannot create sample buffer");
556 qWarning(
"failed to connect sample buffer");
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'",
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'",
578 #ifdef OPUS_SET_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'",
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'",
612 qsrand(QTime::currentTime().msec() ^ qrand());
613 ogg_stream_init(&
m_os, qrand());
619 static inline void _writeInt(QBuffer &buffer, quint32 value)
621 quint32 x = qToLittleEndian<quint32>(value);
622 buffer.write(reinterpret_cast<const char *>(&x),
sizeof(x));
628 Kwave::opus_header_t header;
632 memset(&header, 0x00,
sizeof(header));
633 memset(&header.map, 0xFF,
sizeof(header.map));
635 memcpy(&(header.magic[0]),
"OpusHead", 8);
638 header.preskip = qToLittleEndian<quint16>(
m_opus_header.preskip);
639 header.sample_rate = qToLittleEndian<quint32>(
m_opus_header.sample_rate);
654 m_op.packet =
reinterpret_cast<unsigned char *
>(&header);
662 while (ogg_stream_flush(&
m_os, &
m_og)) {
663 dst.write(reinterpret_cast<char *>(
m_og.header),
665 dst.write(reinterpret_cast<char *>(
m_og.body),
677 buffer.open(QBuffer::ReadWrite);
680 buffer.write(
"OpusTags", 8);
683 const char *opus_version = opus_get_version_string();
684 quint32 len = quint32(strlen(opus_version));
686 buffer.write(opus_version, len);
689 QList<QByteArray> tags;
696 QString str = key +
_(
"=") +
m_info.
get(property).toString();
697 QByteArray v = str.toUtf8();
705 len += (4 + v.size());
712 foreach (
const QByteArray &tag, tags) {
717 m_op.packet =
reinterpret_cast<unsigned char *
>(buffer.buffer().data());
718 m_op.bytes =
static_cast<long int>(buffer.size());
725 while (ogg_stream_flush(&
m_os, &
m_og)) {
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));
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));
766 QApplication::processEvents();
781 unsigned int count = 0;
790 const unsigned int avail = buf->
available();
795 unsigned int len = qMin<unsigned int>(rest, avail);
808 if (count < min_count) min_count = count;
812 unsigned int n = (min_count <=
m_frame_size) ? min_count : 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;
850 int size_segments = 0;
854 if (nb_samples < 0) {
856 total_samples += nb_samples;
863 const unsigned int pad_from =
865 const unsigned int pad_to =
867 for (
unsigned int pos = pad_from; pos < pad_to; pos++ )
872 int nbBytes = opus_multistream_encode_float(
880 qWarning(
"Opus encoder failed: '%s'",
887 total_bytes += nbBytes;
888 size_segments = (nbBytes + 255) / 255;
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))
901 if (ogg_page_packets(&
m_og) != 0)
902 last_granulepos = ogg_page_granulepos(&
m_og);
904 last_segments -=
m_og.header[26];
907 qWarning(
"Opus encoder: I/O error");
917 if ((!
m_op.e_o_s ) && (max_ogg_delay > 5760)) {
919 total_samples += nb_samples;
921 if (nb_samples == 0)
m_op.e_o_s = 1;
927 m_op.packetno = packet_id;
928 m_op.bytes = nbBytes;
930 m_op.granulepos = enc_granulepos;
937 m_op.granulepos =
static_cast<ogg_int64_t
>(
941 last_segments += size_segments;
945 while ((
m_op.e_o_s || (enc_granulepos +
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))
959 if (ogg_page_packets(&
m_og) != 0)
960 last_granulepos = ogg_page_granulepos(&
m_og);
962 last_segments -=
m_og.header[26];
964 qWarning(
"Opus encoder: I/O error");
988 ogg_stream_clear(&
m_os);
Kwave::opus_header_t m_opus_header
bool contains(const FileProperty property) const
int opus_next_sample_rate(int rate)
virtual bool writeHeader(QIODevice &dst) Q_DECL_OVERRIDE
virtual const sample_t * get(unsigned int len)
unsigned int fillInBuffer(Kwave::MultiTrackReader &src)
Kwave::StreamObject * m_rate_converter
static void _writeInt(QBuffer &buffer, quint32 value)
bool writeOggPage(QIODevice &dst)
Kwave::VorbisCommentMap m_comments_map
QVariant get(FileProperty key) const
static int sorry(QWidget *widget, QString message, QString caption=QString())
bool writeOpusTags(QIODevice &dst)
bool setupBitrate(QWidget *widget, unsigned int tracks)
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
virtual void goOn() Q_DECL_OVERRIDE
Kwave::MultiTrackSink< Kwave::SampleBuffer, true > * m_buffer
unsigned int m_encoder_channels
static int error(QWidget *widget, QString message, QString caption=QString())
bool writeOpusHeader(QIODevice &dst)
sample_index_t length() const
unsigned int m_max_frame_bytes
Kwave::ChannelMixer * m_channel_mixer
virtual bool encode(Kwave::MultiTrackReader &src, QIODevice &dst) Q_DECL_OVERRIDE
bool setupEncoder(QWidget *widget, unsigned int tracks, double rate)
Kwave::StreamObject * m_last_queue_element
QString opus_error(int err)
static float sample2float(const sample_t s)
static int warningContinueCancel(QWidget *widget, QString message, QString caption=QString(), const QString buttonContinue=QString(), const QString buttonCancel=QString(), const QString &dontAskAgainName=QString())
unsigned int tracks() const
bool setupCodingRate(QWidget *widget, unsigned int tracks, double rate)
unsigned int m_frame_size
virtual void close() Q_DECL_OVERRIDE
#define DEFAULT_COMPLEXITY
bool setupDownMix(QWidget *widget, unsigned int tracks, int bitrate)
virtual unsigned int available() const
unsigned char * m_packet_buffer
OpusMSEncoder * m_encoder
unsigned int bits() const
virtual bool open(QWidget *widget, const Kwave::FileInfo &info, Kwave::MultiTrackReader &src) Q_DECL_OVERRIDE
virtual ~OpusEncoder() Q_DECL_OVERRIDE
bool setupBitrateMode(QWidget *widget)
virtual SINK * at(unsigned int track) const
void setAttribute(const char *attribute, const QVariant &value)
enum Kwave::OpusEncoder::@12 m_downmix