00001
00002 #include <vorbis/vorbisfile.h>
00003
00004
00005 #include <time.h>
00006
00007
00008 #include <cstdlib>
00009
00010
00011 #include <iostream>
00012 using namespace std;
00013
00014
00015 #include <QApplication>
00016 #include <QString>
00017
00018
00019 #include <mythcontext.h>
00020 #include <compat.h>
00021
00022
00023 #include "metadata.h"
00024 #include "encoder.h"
00025 #include "vorbisencoder.h"
00026 #include "metaiooggvorbis.h"
00027
00028
00029 static int write_page(ogg_page *page, FILE *fp)
00030 {
00031 int written = fwrite(page->header, 1, page->header_len, fp);
00032 written += fwrite(page->body, 1, page->body_len, fp);
00033
00034 return written;
00035 }
00036
00037 VorbisEncoder::VorbisEncoder(const QString &outfile, int qualitylevel,
00038 Metadata *metadata) :
00039 Encoder(outfile, qualitylevel, metadata),
00040 packetsdone(0),
00041 eos(0),
00042 bytes_written(0L),
00043 m_metadata(metadata)
00044 {
00045 vorbis_comment_init(&vc);
00046
00047 vorbis_info_init(&vi);
00048
00049 float quality = 1.0;
00050 if (qualitylevel == 0)
00051 quality = 0.4;
00052 if (qualitylevel == 1)
00053 quality = 0.7;
00054
00055 int ret = vorbis_encode_setup_vbr(&vi, 2, 44100, quality);
00056 if (ret)
00057 {
00058 LOG(VB_GENERAL, LOG_ERR, QString("Error initializing VORBIS encoder."
00059 " Got return code: %1").arg(ret));
00060 vorbis_info_clear(&vi);
00061 return;
00062 }
00063
00064 vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_SET, NULL);
00065 vorbis_encode_setup_init(&vi);
00066 vorbis_analysis_init(&vd, &vi);
00067 vorbis_block_init(&vd, &vb);
00068
00069 ogg_stream_init(&os, random());
00070
00071 ogg_packet header_main;
00072 ogg_packet header_comments;
00073 ogg_packet header_codebooks;
00074
00075 vorbis_analysis_headerout(&vd, &vc, &header_main, &header_comments,
00076 &header_codebooks);
00077
00078 ogg_stream_packetin(&os, &header_main);
00079 ogg_stream_packetin(&os, &header_comments);
00080 ogg_stream_packetin(&os, &header_codebooks);
00081
00082 int result;
00083 while ((result = ogg_stream_flush(&os, &og)))
00084 {
00085 if (!result || !m_out)
00086 break;
00087 int ret = write_page(&og, m_out);
00088 if (ret != og.header_len + og.body_len)
00089 {
00090 LOG(VB_GENERAL, LOG_ERR,
00091 "Failed to write header to output stream.");
00092 }
00093 }
00094 }
00095
00096 VorbisEncoder::~VorbisEncoder()
00097 {
00098 addSamples(0, 0);
00099 ogg_stream_clear(&os);
00100 vorbis_block_clear(&vb);
00101 vorbis_dsp_clear(&vd);
00102 vorbis_comment_clear(&vc);
00103 vorbis_info_clear(&vi);
00104
00105
00106 if (m_metadata)
00107 {
00108 QString filename = m_metadata->Filename();
00109 m_metadata->setFilename(m_outfile);
00110 MetaIOOggVorbis().write(m_metadata);
00111 m_metadata->setFilename(filename);
00112 }
00113 }
00114
00115 int VorbisEncoder::addSamples(int16_t * bytes, unsigned int length)
00116 {
00117 int i;
00118 long realsamples = 0;
00119 signed char *chars = (signed char *)bytes;
00120
00121 realsamples = length / 4;
00122
00123 if (!m_out)
00124 return 0;
00125
00126 float** buffer = vorbis_analysis_buffer(&vd, realsamples);
00127
00128 for (i = 0; i < realsamples; i++)
00129 {
00130 buffer[0][i] = ((chars[i * 4 + 1] << 8) |
00131 (chars[i * 4] & 0xff)) / 32768.0f;
00132 buffer[1][i] = ((chars[i * 4 + 3] << 8) |
00133 (chars[i * 4 + 2] & 0xff)) / 32768.0f;
00134 }
00135
00136 vorbis_analysis_wrote(&vd, realsamples);
00137
00138 while (vorbis_analysis_blockout(&vd, &vb) == 1)
00139 {
00140 vorbis_analysis(&vb, NULL);
00141 vorbis_bitrate_addblock(&vb);
00142
00143 while (vorbis_bitrate_flushpacket(&vd, &op))
00144 {
00145 ogg_stream_packetin(&os, &op);
00146 packetsdone++;
00147
00148 int eos = 0;
00149 while (!eos)
00150 {
00151 int result = ogg_stream_pageout(&os, &og);
00152 if (!result)
00153 break;
00154
00155 int ret = write_page(&og, m_out);
00156 if (ret != og.header_len + og.body_len)
00157 {
00158 LOG(VB_GENERAL, LOG_ERR,
00159 QString("Failed to write ogg data. Aborting."));
00160 return EENCODEERROR;
00161 }
00162 bytes_written += ret;
00163
00164 if (ogg_page_eos(&og))
00165 eos = 1;
00166 }
00167 }
00168 }
00169
00170 return 0;
00171 }