MythTV  master
vorbisencoder.cpp
Go to the documentation of this file.
1 // System
2 #include <vorbis/vorbisfile.h>
3 
4 // C++
5 #include <cstdlib>
6 #include <ctime>
7 #include <iostream>
8 
9 // Qt
10 #include <QApplication>
11 #include <QString>
12 
13 // MythTV
14 #include <mythcontext.h>
15 #include <compat.h> // For random() on MINGW32
16 #include <musicmetadata.h>
17 
18 // MythMusic
19 #include "encoder.h"
20 #include "vorbisencoder.h"
21 #include "metaiooggvorbis.h"
22 
23 
24 static int write_page(ogg_page *page, FILE *fp)
25 {
26  int written = fwrite(page->header, 1, page->header_len, fp);
27  written += fwrite(page->body, 1, page->body_len, fp);
28 
29  return written;
30 }
31 
32 VorbisEncoder::VorbisEncoder(const QString &outfile, int qualitylevel,
33  MusicMetadata *metadata) :
34  Encoder(outfile, qualitylevel, metadata)
35 {
36  vorbis_comment_init(&m_vc);
37 
38  vorbis_info_init(&m_vi);
39 
40  ogg_packet_clear(&m_op);
41 
42  float quality = 1.0;
43  if (qualitylevel == 0)
44  quality = 0.4;
45  if (qualitylevel == 1)
46  quality = 0.7;
47 
48  int ret = vorbis_encode_setup_vbr(&m_vi, 2, 44100, quality);
49  if (ret)
50  {
51  LOG(VB_GENERAL, LOG_ERR, QString("Error initializing VORBIS encoder."
52  " Got return code: %1").arg(ret));
53  vorbis_info_clear(&m_vi);
54  return;
55  }
56 
57  vorbis_encode_ctl(&m_vi, OV_ECTL_RATEMANAGE_SET, nullptr);
58  vorbis_encode_setup_init(&m_vi);
59  vorbis_analysis_init(&m_vd, &m_vi);
60  vorbis_block_init(&m_vd, &m_vb);
61 
62  ogg_stream_init(&m_os, random());
63 
64  ogg_packet header_main;
65  ogg_packet header_comments;
66  ogg_packet header_codebooks;
67 
68  vorbis_analysis_headerout(&m_vd, &m_vc, &header_main, &header_comments,
69  &header_codebooks);
70 
71  ogg_stream_packetin(&m_os, &header_main);
72  ogg_stream_packetin(&m_os, &header_comments);
73  ogg_stream_packetin(&m_os, &header_codebooks);
74 
75  int result = 0;
76  while ((result = ogg_stream_flush(&m_os, &m_og)))
77  {
78  if (!result || !m_out)
79  break;
80  int ret2 = write_page(&m_og, m_out);
81  if (ret2 != m_og.header_len + m_og.body_len)
82  {
83  LOG(VB_GENERAL, LOG_ERR,
84  "Failed to write header to output stream.");
85  }
86  }
87 }
88 
90 {
91  VorbisEncoder::addSamples(nullptr, 0); //flush
92  ogg_stream_clear(&m_os);
93  vorbis_block_clear(&m_vb);
94  vorbis_dsp_clear(&m_vd);
95  vorbis_comment_clear(&m_vc);
96  vorbis_info_clear(&m_vi);
97 
98  // Now write the Metadata
99  if (m_metadata)
101 }
102 
103 int VorbisEncoder::addSamples(int16_t * bytes, unsigned int length)
104 {
105  long realsamples = 0;
106  auto *chars = (signed char *)bytes;
107 
108  realsamples = length / 4;
109 
110  if (!m_out)
111  return 0;
112 
113  float** buffer = vorbis_analysis_buffer(&m_vd, realsamples);
114 
115  for (long i = 0; i < realsamples; i++)
116  {
117  buffer[0][i] = ((chars[i * 4 + 1] << 8) |
118  (chars[i * 4] & 0xff)) / 32768.0F;
119  buffer[1][i] = ((chars[i * 4 + 3] << 8) |
120  (chars[i * 4 + 2] & 0xff)) / 32768.0F;
121  }
122 
123  vorbis_analysis_wrote(&m_vd, realsamples);
124 
125  while (vorbis_analysis_blockout(&m_vd, &m_vb) == 1)
126  {
127  vorbis_analysis(&m_vb, nullptr);
128  vorbis_bitrate_addblock(&m_vb);
129 
130  while (vorbis_bitrate_flushpacket(&m_vd, &m_op))
131  {
132  ogg_stream_packetin(&m_os, &m_op);
133  m_packetsDone++;
134 
135  int eos = 0;
136  while (!eos)
137  {
138  int result = ogg_stream_pageout(&m_os, &m_og);
139  if (!result)
140  break;
141 
142  int ret = write_page(&m_og, m_out);
143  if (ret != m_og.header_len + m_og.body_len)
144  {
145  LOG(VB_GENERAL, LOG_ERR,
146  QString("Failed to write ogg data. Aborting."));
147  return EENCODEERROR;
148  }
149  m_bytesWritten += ret;
150 
151  if (ogg_page_eos(&m_og))
152  eos = 1;
153  }
154  }
155  }
156 
157  return 0;
158 }
VorbisEncoder::VorbisEncoder
VorbisEncoder(const QString &outfile, int qualitylevel, MusicMetadata *metadata)
Definition: vorbisencoder.cpp:32
VorbisEncoder::m_vb
vorbis_block m_vb
Definition: vorbisencoder.h:26
VorbisEncoder::m_vd
vorbis_dsp_state m_vd
Definition: vorbisencoder.h:25
VorbisEncoder::m_op
ogg_packet m_op
Definition: vorbisencoder.h:19
VorbisEncoder::m_vi
vorbis_info m_vi
Definition: vorbisencoder.h:27
vorbisencoder.h
Encoder
Definition: mythplugins/mythmusic/mythmusic/encoder.h:13
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MusicMetadata
Definition: musicmetadata.h:80
EENCODEERROR
#define EENCODEERROR
Definition: mythplugins/mythmusic/mythmusic/encoder.h:7
MetaIOOggVorbis::write
bool write(const QString &filename, MusicMetadata *mdata) override
Writes all metadata back to a file.
Definition: metaiooggvorbis.cpp:34
mythburn.FILE
int FILE
Definition: mythburn.py:139
VorbisEncoder::m_os
ogg_stream_state m_os
Definition: vorbisencoder.h:23
VorbisEncoder::m_bytesWritten
long m_bytesWritten
Definition: vorbisencoder.h:21
compat.h
MetaIOOggVorbis
Read and write Vorbis (Xiph) tags in an Ogg container.
Definition: metaiooggvorbis.h:21
VorbisEncoder::m_packetsDone
long m_packetsDone
Definition: vorbisencoder.h:20
VorbisEncoder::m_og
ogg_page m_og
Definition: vorbisencoder.h:18
Encoder::m_metadata
MusicMetadata * m_metadata
Definition: mythplugins/mythmusic/mythmusic/encoder.h:26
musicbrainzngs.compat.bytes
bytes
Definition: compat.py:49
encoder.h
random
static long int random(void)
Definition: compat.h:161
VorbisEncoder::addSamples
int addSamples(int16_t *bytes, unsigned int len) override
Definition: vorbisencoder.cpp:103
mythcontext.h
Encoder::m_outfile
const QString m_outfile
Definition: mythplugins/mythmusic/mythmusic/encoder.h:23
VorbisEncoder::m_vc
vorbis_comment m_vc
Definition: vorbisencoder.h:22
write_page
static int write_page(ogg_page *page, FILE *fp)
Definition: vorbisencoder.cpp:24
VorbisEncoder::~VorbisEncoder
~VorbisEncoder() override
Definition: vorbisencoder.cpp:89
musicmetadata.h
metaiooggvorbis.h
Encoder::m_out
FILE * m_out
Definition: mythplugins/mythmusic/mythmusic/encoder.h:24