MythTV  0.26-pre
vorbisencoder.cpp
Go to the documentation of this file.
00001 // System
00002 #include <vorbis/vorbisfile.h>
00003 
00004 // POSIX
00005 #include <time.h>
00006 
00007 // ANSI C
00008 #include <cstdlib>
00009 
00010 // C++
00011 #include <iostream>
00012 using namespace std;
00013 
00014 // Qt
00015 #include <QApplication>
00016 #include <QString>
00017 
00018 // MythTV
00019 #include <mythcontext.h>
00020 #include <compat.h> // For random() on MINGW32
00021 
00022 // MythMusic
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); //flush
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     // Now write the Metadata
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends