⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vorbislmc.cpp

📁 FreeAMP(MP3播放)程序源代码-用来研究MP3解码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*____________________________________________________________________________
   
   FreeAmp - The Free MP3 Player

   Portions Copyright (C) 2000 Monty

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, Write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   
   $Id: vorbislmc.cpp,v 1.17 2001/03/08 09:46:05 robert Exp $
____________________________________________________________________________*/

/* system headers */
#include <stdlib.h>
#include <stdio.h>
#include <iostream.h>
#include <assert.h>
#include <string.h>
#include <math.h>

#include "config.h"
#include "errors.h"
#include "pmoevent.h"
#include "eventbuffer.h"
#include "event.h"
#include "eventdata.h"
#include "mutex.h"
#include "semaphore.h"
#include "preferences.h"
#include "lmc.h"
#include "facontext.h"
#include "log.h"
#include "debug.h"

#include "vorbislmc.h" 

#define DB printf("%s:%d\n",  __FILE__, __LINE__);

extern    "C"
{
   LogicalMediaConverter *Initialize(FAContext *context)
   {
      return new VorbisLMC(context);
   }
}

const int iDecodeBlockSize = 8192;
const int iFramesPerSecond = 10;
const int iBitrateLoopsPerUpdate = iFramesPerSecond * 3;
const int iInitialOutputBufferSize = 64512; 
const char *szFailRead = "Cannot read vorbis data from input plugin.";
const char *szFailWrite = "Cannot write audio data to output buffer.";
const char *szCannotDecode = "Skipped corrupted file.";

VorbisLMC::VorbisLMC(FAContext *context) :
         LogicalMediaConverter(context)
{
   m_pContext = context;

   m_decoderThread = NULL;
   m_szUrl = NULL;
   m_szError = NULL;
   m_bInit = false;
   m_newPos = -1;
   m_decodeInfo.sendInfo = true;
}

VorbisLMC::~VorbisLMC()
{
   if (m_decoderThread)
   {
      m_bExit = true;
      m_pPauseSem->Signal();
      m_pSleepSem->Signal();

      m_decoderThread->Join();

      delete m_decoderThread;
      m_decoderThread = NULL;
   }
}

Error VorbisLMC::Prepare(PullBuffer *pInputBuffer, PullBuffer *&pOutBuffer)
{
   m_pInputBuffer = pInputBuffer;


   m_pOutputBuffer = new EventBuffer(iInitialOutputBufferSize, 0, 
                                    m_pContext);
   if (!m_decoderThread)
   {
      m_decoderThread = Thread::CreateThread();
      if (!m_decoderThread)
      {
         return kError_CreateThreadFailed;
      }
      m_decoderThread->Create(VorbisLMC::DecodeWorkerThreadFunc, this);
   }

   pOutBuffer =  m_pOutputBuffer;

   m_pInputBuffer->SetName("Input");
   m_pOutputBuffer->SetName("Output");

   return kError_NoErr;
}

void VorbisLMC::Clear()
{
   if (m_pOutputBuffer)
      ((EventBuffer *)m_pOutputBuffer)->Clear();
}

vector<string> *VorbisLMC::GetExtensions(void)
{
   vector<string> *extList = new vector<string>;

   extList->push_back("OGG");

   return extList;
}

Error VorbisLMC::CanDecode()
{
   Error err;

   if (!m_bInit)
   {
       err = InitDecoder();
       if (err != kError_NoErr)
           return err;
   }

   return kError_NoErr;
}

Error VorbisLMC::InitDecoder()
{
   ov_callbacks     callbacks;
   vorbis_info     *vi;
   Error            result;
   int              iNewSize;

   if (!m_pTarget || !m_pPmi || !m_pPmo || !m_pInputBuffer || !m_pOutputBuffer)
   {
      return kError_PluginNotInitialized;
   }

   memset(&m_vf, 0, sizeof(m_vf));
   callbacks.read_func = VorbisLMC::ReadWrapper;
   callbacks.seek_func = VorbisLMC::SeekWrapper;
   callbacks.close_func = VorbisLMC::CloseWrapper;
   callbacks.tell_func = VorbisLMC::TellWrapper;    

   if (ov_open_callbacks(this, &m_vf, NULL, 0, callbacks) < 0)
       return kError_UnknownErr;

   vi = ov_info(&m_vf, -1);
   m_channels = vi->channels;
   m_rate = vi->rate;
   m_section = -1;

   m_pContext->prefs->GetPrefInt32(kOutputBufferSizePref, &iNewSize);
   iNewSize = max(iNewSize, iMinimumOutputBufferSize);
   iNewSize *= 1024;

   result = m_pOutputBuffer->Resize(iNewSize, iNewSize / 6);
   if (IsError(result))
   {
       ReportError("Internal buffer sizing error occurred.");
       m_pContext->log->Error("Resize output buffer failed.");
       return result;
   }   
   m_bInit = true;

   return kError_NoErr;
}
 
Error VorbisLMC::ExtractMediaInfo()
{
   Error           err;
   float           totalSeconds;
   MediaInfoEvent *pMIE;
   vorbis_info    *vi;

   if (!m_bInit)
   {
       err = InitDecoder();
       if (err != kError_NoErr)
           return err;
   }

   totalSeconds = ov_time_total(&m_vf, 0);

   vi = ov_info(&m_vf, -1);
   pMIE = new MediaInfoEvent(m_pPmi->Url(), totalSeconds);
   if (!pMIE)
      return kError_OutOfMemory;

   VorbisInfoEvent *mie = new VorbisInfoEvent(ov_bitrate(&m_vf, 0),
                                              vi->channels, 
                                              vi->rate, 
                                              1. / (float)iFramesPerSecond);
   if (mie)
   {
       pMIE->AddChildEvent((Event *) mie);
       mie = NULL;
   }
   else
   {
       return kError_OutOfMemory;
   }

   if (m_pTarget)
      m_pTarget->AcceptEvent(pMIE);

   return kError_NoErr;
}

uint32 VorbisLMC::CalculateSongLength(const char *url)
{
    char            path[_MAX_PATH];
    uint32          len = _MAX_PATH;
    FILE           *fpFile;
    OggVorbis_File  vf;
    double          dur;

    URLToFilePath(url, path, &len);
    fpFile = fopen(path, "rb");
    if (fpFile == NULL)
       return 0;  

    memset(&vf, 0, sizeof(vf));
    if (ov_open(fpFile, &vf, NULL, 0) < 0)
    {
       fclose(fpFile);
       return 0; 
    }

    dur = ov_time_total(&vf, 0);

    ov_clear(&vf);

    return (int)dur;
}

void VorbisLMC::DecodeWorkerThreadFunc(void *pxlmc)
{
   if (pxlmc)
   {
      VorbisLMC  *xlmc = (VorbisLMC *) pxlmc;

      xlmc->DecodeWork();
   }
}

void VorbisLMC::DecodeWork()
{
   void          *pOutBuffer;
   Error          Err;
   int32          iValue;
   int32          section, ret;
   OutputInfo    *info;
   vorbis_info   *vi;
   uint32         bytesCopied, bytesPerFrame;
   int            bitrateLoops = 0;

   assert(m_pPmi);
   assert(m_pPmo);

   m_pSleepSem->Wait();
   m_pPmi->Wake();

   Err = CanDecode();
   if (Err == kError_Interrupt)
      return;
   if (Err != kError_NoErr)
   {
       m_pContext->log->Error("CanDecode returned false.\n");
       if (m_decodeInfo.sendInfo)
       {
           ReportStatus(szCannotDecode);
           m_pTarget->AcceptEvent(new Event(INFO_DoneOutputtingDueToError));
       }
       else
           ((EventBuffer *)m_pOutputBuffer)->AcceptEvent(new PMOErrorEvent());
       return;
   }

   Err = ExtractMediaInfo();
   if (Err == kError_Interrupt)
      return;

   if (IsError(Err))
   {
       m_pContext->log->Error("ExtractMediaInfo failed: %d\n", Err);
       if (m_decodeInfo.sendInfo)
       {
           ReportStatus(szCannotDecode);
           m_pTarget->AcceptEvent(new Event(INFO_DoneOutputtingDueToError));
       }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -