Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/recording/encodervorbis.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002                    encodervorbis.cpp  -  vorbis encoder for mixxx
00003                              -------------------
00004     copyright            : (C) 2007 by Wesley Stessens
00005                            (C) 1994 by Xiph.org (encoder example)
00006                            (C) 1994 Tobias Rafreider (shoutcast and recording fixes)
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 /*
00019 Okay, so this is the vorbis encoder class...
00020 It's a real mess right now.
00021 
00022 When I get around to cleaning things up,
00023 I'll probably make an Encoder base class,
00024 so we can easily add in an EncoderLame (or something) too.
00025 
00026 A lot of stuff has been stolen from:
00027 http://svn.xiph.org/trunk/vorbis/examples/encoder_example.c
00028 */
00029 
00030 // TODO: MORE ERROR CHECKING EVERYWHERE (encoder and shoutcast classes)
00031 
00032 #include "recording/encodervorbis.h"
00033 
00034 #include <stdlib.h> // needed for random num gen
00035 #include <time.h> // needed for random num gen
00036 #include <string.h> // needed for memcpy
00037 #include <QDebug>
00038 
00039 #include "engine/engineabstractrecord.h"
00040 #include "controlobjectthreadmain.h"
00041 #include "controlobject.h"
00042 #include "playerinfo.h"
00043 #include "trackinfoobject.h"
00044 #include "errordialoghandler.h"
00045 
00046 // Constructor
00047 EncoderVorbis::EncoderVorbis(EngineAbstractRecord *engine) {
00048     m_bStreamInitialized = false;
00049     m_pEngine = engine;
00050     m_metaDataTitle = NULL;
00051     m_metaDataArtist = NULL;
00052     m_metaDataAlbum = NULL;
00053     m_pMetaData = TrackPointer(NULL);
00054     m_samplerate = new ControlObjectThread(ControlObject::getControl(ConfigKey("[Master]", "samplerate")));
00055 }
00056 
00057 // Destructor  //call flush before any encoder gets deleted
00058 EncoderVorbis::~EncoderVorbis() {
00059     if (m_bStreamInitialized) {
00060         ogg_stream_clear(&m_oggs);
00061         vorbis_block_clear(&m_vblock);
00062         vorbis_dsp_clear(&m_vdsp);
00063         vorbis_comment_clear(&m_vcomment);
00064         vorbis_info_clear(&m_vinfo);
00065     }
00066     delete m_samplerate;
00067 }
00068 //call sendPackages() or write() after 'flush()' as outlined in engineshoutcast.cpp
00069 void EncoderVorbis::flush() {
00070     vorbis_analysis_wrote(&m_vdsp, 0);
00071     writePage();
00072 }
00073 
00074 /*
00075   Get new random serial number
00076   -> returns random number
00077 */
00078 int EncoderVorbis::getSerial()
00079 {
00080     static int prevSerial = 0;
00081     int serial = rand();
00082     while (prevSerial == serial)
00083         serial = rand();
00084     prevSerial = serial;
00085     qDebug() << "RETURNING SERIAL " << serial;
00086     return serial;
00087 }
00088 
00089 void EncoderVorbis::writePage() {
00090 
00091     /*
00092                  * Vorbis streams begin with three headers; the initial header (with
00093      * most of the codec setup parameters) which is mandated by the Ogg
00094      * bitstream spec.  The second header holds any comment fields.  The
00095      * third header holds the bitstream codebook.  We merely need to
00096      * make the headers, then pass them to libvorbis one at a time;
00097      * libvorbis handles the additional Ogg bitstream constraints
00098                  */
00099 
00100 
00101     //Write header only once after stream has been initalized
00102     int result;
00103     if(m_header_write){
00104         while (1) {
00105             result = ogg_stream_flush(&m_oggs, &m_oggpage);
00106             if (result==0) break;
00107             m_pEngine->write(m_oggpage.header, m_oggpage.body, m_oggpage.header_len, m_oggpage.body_len);
00108         }
00109         m_header_write = false;
00110     }
00111 
00112     while (vorbis_analysis_blockout(&m_vdsp, &m_vblock) == 1) {
00113         vorbis_analysis(&m_vblock, 0);
00114         vorbis_bitrate_addblock(&m_vblock);
00115         while (vorbis_bitrate_flushpacket(&m_vdsp, &m_oggpacket)) {
00116             // weld packet into bitstream
00117             ogg_stream_packetin(&m_oggs, &m_oggpacket);
00118             // write out pages
00119             int eos = 0;
00120             while (!eos) {
00121                 int result = ogg_stream_pageout(&m_oggs, &m_oggpage);
00122                 if (result == 0) break;
00123                 m_pEngine->write(m_oggpage.header, m_oggpage.body, m_oggpage.header_len, m_oggpage.body_len);
00124                 if (ogg_page_eos(&m_oggpage)) eos = 1;
00125             }
00126         }
00127     }
00128 }
00129 
00130 void EncoderVorbis::encodeBuffer(const CSAMPLE *samples, const int size) {
00131     float **buffer;
00132     int i;
00133 
00134     buffer = vorbis_analysis_buffer(&m_vdsp, size);
00135 
00136     // Deinterleave samples
00137     for (i = 0; i < size/2; ++i)
00138     {
00139         buffer[0][i] = samples[i*2]/32768.f;
00140         buffer[1][i] = samples[i*2+1]/32768.f;
00141     }
00143     vorbis_analysis_wrote(&m_vdsp, i);
00145     writePage();
00146 }
00147 
00148 /* Originally called from engineshoutcast.cpp to update metadata information
00149  * when streaming, however, this causes pops
00150  *
00151  * Currently this method is used before init() once to save artist, title and album
00152 */
00153 void EncoderVorbis::updateMetaData(char* artist, char* title, char* album) {
00154     m_metaDataTitle = title;
00155     m_metaDataArtist = artist;
00156     m_metaDataAlbum = album;
00157 }
00158 
00159 void EncoderVorbis::initStream() {
00160     // set up analysis state and auxiliary encoding storage
00161     vorbis_analysis_init(&m_vdsp, &m_vinfo);
00162     vorbis_block_init(&m_vdsp, &m_vblock);
00163 
00164     // set up packet-to-stream encoder; attach a random serial number
00165     srand(time(0));
00166     ogg_stream_init(&m_oggs, getSerial());
00167 
00168     // add comment
00169     vorbis_comment_init(&m_vcomment);
00170     vorbis_comment_add_tag(&m_vcomment, "ENCODER", "mixxx/libvorbis");
00171     if (m_metaDataArtist != NULL)
00172         vorbis_comment_add_tag(&m_vcomment, "ARTIST", m_metaDataArtist);
00173     if (m_metaDataTitle != NULL)
00174         vorbis_comment_add_tag(&m_vcomment, "TITLE", m_metaDataTitle);
00175                 if (m_metaDataAlbum != NULL)
00176         vorbis_comment_add_tag(&m_vcomment, "ALBUM", m_metaDataAlbum);
00177 
00178     // set up the vorbis headers
00179     ogg_packet headerInit;
00180     ogg_packet headerComment;
00181     ogg_packet headerCode;
00182     vorbis_analysis_headerout(&m_vdsp, &m_vcomment, &headerInit, &headerComment, &headerCode);
00183     ogg_stream_packetin(&m_oggs, &headerInit);
00184     ogg_stream_packetin(&m_oggs, &headerComment);
00185     ogg_stream_packetin(&m_oggs, &headerCode);
00186 
00187                 //The encoder is now inialized
00188                 // Encode method will start streaming by sending the header first
00189                 m_header_write = true;
00190     m_bStreamInitialized = true;
00191 }
00192 
00193 int EncoderVorbis::initEncoder(int bitrate) {
00194     int ret;
00195     vorbis_info_init(&m_vinfo);
00196 
00197     // initialize VBR quality based mode
00198     unsigned long samplerate = m_samplerate->get();
00199 
00200     ret = vorbis_encode_init(&m_vinfo, 2, samplerate, -1, bitrate*1000, -1);
00201 
00202     if (ret == 0) {
00203         initStream();
00204     } else {
00205         ret = -1;
00206     };
00207     return ret;
00208 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines