MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
vorbisencoder.cpp
Go to the documentation of this file.
1 // System
2 #include <vorbis/vorbisfile.h>
3 
4 // POSIX
5 #include <time.h>
6 
7 // ANSI C
8 #include <cstdlib>
9 
10 // C++
11 #include <iostream>
12 using namespace std;
13 
14 // Qt
15 #include <QApplication>
16 #include <QString>
17 
18 // MythTV
19 #include <mythcontext.h>
20 #include <compat.h> // For random() on MINGW32
21 #include <musicmetadata.h>
22 
23 // MythMusic
24 #include "encoder.h"
25 #include "vorbisencoder.h"
26 #include "metaiooggvorbis.h"
27 
28 
29 static int write_page(ogg_page *page, FILE *fp)
30 {
31  int written = fwrite(page->header, 1, page->header_len, fp);
32  written += fwrite(page->body, 1, page->body_len, fp);
33 
34  return written;
35 }
36 
37 VorbisEncoder::VorbisEncoder(const QString &outfile, int qualitylevel,
38  MusicMetadata *metadata) :
39  Encoder(outfile, qualitylevel, metadata),
40  packetsdone(0),
41  eos(0),
42  bytes_written(0L),
43  m_metadata(metadata)
44 {
45  vorbis_comment_init(&vc);
46 
47  vorbis_info_init(&vi);
48 
49  float quality = 1.0;
50  if (qualitylevel == 0)
51  quality = 0.4;
52  if (qualitylevel == 1)
53  quality = 0.7;
54 
55  int ret = vorbis_encode_setup_vbr(&vi, 2, 44100, quality);
56  if (ret)
57  {
58  LOG(VB_GENERAL, LOG_ERR, QString("Error initializing VORBIS encoder."
59  " Got return code: %1").arg(ret));
60  vorbis_info_clear(&vi);
61  return;
62  }
63 
64  vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_SET, NULL);
65  vorbis_encode_setup_init(&vi);
66  vorbis_analysis_init(&vd, &vi);
67  vorbis_block_init(&vd, &vb);
68 
69  ogg_stream_init(&os, random());
70 
71  ogg_packet header_main;
72  ogg_packet header_comments;
73  ogg_packet header_codebooks;
74 
75  vorbis_analysis_headerout(&vd, &vc, &header_main, &header_comments,
76  &header_codebooks);
77 
78  ogg_stream_packetin(&os, &header_main);
79  ogg_stream_packetin(&os, &header_comments);
80  ogg_stream_packetin(&os, &header_codebooks);
81 
82  int result;
83  while ((result = ogg_stream_flush(&os, &og)))
84  {
85  if (!result || !m_out)
86  break;
87  int ret = write_page(&og, m_out);
88  if (ret != og.header_len + og.body_len)
89  {
90  LOG(VB_GENERAL, LOG_ERR,
91  "Failed to write header to output stream.");
92  }
93  }
94 }
95 
97 {
98  addSamples(0, 0); //flush
99  ogg_stream_clear(&os);
100  vorbis_block_clear(&vb);
101  vorbis_dsp_clear(&vd);
102  vorbis_comment_clear(&vc);
103  vorbis_info_clear(&vi);
104 
105  // Now write the Metadata
106  if (m_metadata)
107  {
108  QString filename = m_metadata->Filename();
111  m_metadata->setFilename(filename);
112  }
113 }
114 
115 int VorbisEncoder::addSamples(int16_t * bytes, unsigned int length)
116 {
117  int i;
118  long realsamples = 0;
119  signed char *chars = (signed char *)bytes;
120 
121  realsamples = length / 4;
122 
123  if (!m_out)
124  return 0;
125 
126  float** buffer = vorbis_analysis_buffer(&vd, realsamples);
127 
128  for (i = 0; i < realsamples; i++)
129  {
130  buffer[0][i] = ((chars[i * 4 + 1] << 8) |
131  (chars[i * 4] & 0xff)) / 32768.0f;
132  buffer[1][i] = ((chars[i * 4 + 3] << 8) |
133  (chars[i * 4 + 2] & 0xff)) / 32768.0f;
134  }
135 
136  vorbis_analysis_wrote(&vd, realsamples);
137 
138  while (vorbis_analysis_blockout(&vd, &vb) == 1)
139  {
140  vorbis_analysis(&vb, NULL);
141  vorbis_bitrate_addblock(&vb);
142 
143  while (vorbis_bitrate_flushpacket(&vd, &op))
144  {
145  ogg_stream_packetin(&os, &op);
146  packetsdone++;
147 
148  int eos = 0;
149  while (!eos)
150  {
151  int result = ogg_stream_pageout(&os, &og);
152  if (!result)
153  break;
154 
155  int ret = write_page(&og, m_out);
156  if (ret != og.header_len + og.body_len)
157  {
158  LOG(VB_GENERAL, LOG_ERR,
159  QString("Failed to write ogg data. Aborting."));
160  return EENCODEERROR;
161  }
162  bytes_written += ret;
163 
164  if (ogg_page_eos(&og))
165  eos = 1;
166  }
167  }
168  }
169 
170  return 0;
171 }