Codec for PCM streams
#1
I have a UPnP Media Server that offers music in the UPnP / DLNA defined default format of 2ch 44100Hz 16bit linear pcm. It offers the music via a url having a .pcm file extension and with mime type audio/L16;rate=44100;channels=2.

Unfortunately it seems that XMBC won't play such a stream. Apprently because there is no codec for such .pcm streams.

Is there a solution?
Reply
#2
add the necessary code to use the mimetype. see the CodecFactory of paplayer.
Reply
#3
spiff Wrote:add the necessary code to use the mimetype
Aha!

A PCM stream is a WAV stream without a RIFF header, so creating a new codec would be a trivial matter of deriving from WavCodec.cpp and overriding its constructor (basically just deleting the code that parses the RIFF header).

However, I am not sure if this is really the way to go, since -- as far as I can tell -- the underlying audio entity structure is PCM anyway (e.g. the ReadPCM method is standard for all codecs). So instead of deriving from WavCodec and removing code, there is perhaps already somewhere a PCMCodec on which everything is already built up? (But not knowing you architecture at all, I could not find this...)

--
AndrewFG
Reply
#4
nope, there's no pure pcm codec as it stands. but reusing the wavcodec would just be a hack, there's not really any code to share. so a new "codec" is probably the cleanest solution.
Reply
#5
spiff Wrote:a new "codec" is probably the cleanest solution.
Ok. Here you go!!

Code:
+++++ PCMCodec.h ++++

#include "ICodec.h"
#include "CachingCodec.h"

class PCMCodec : public CachingCodec
{
public:
  PCMCodec();
  virtual ~PCMCodec();
  virtual bool Init(const CStdString &strFile, unsigned int filecache);
  virtual void DeInit();
  virtual __int64 Seek(__int64 iSeekTime);
  virtual int ReadPCM(BYTE *pBuffer, int size, int *actualsize);
  virtual bool CanInit();
  virtual void SetMimeParams(const CStdString& strMimeParams)
private:
  int iBytesPerSecond;
};



+++++ PCMCodec.cpp +++++

PCMCodec::PCMCodec()
{
  m_CodecName = "PCM";
  m_TotalTime = 0;
  m_SampleRate = 44100;
  m_Channels = 2;
  m_BitsPerSample = 16;
  m_Bitrate = m_SampleRate * m_Channels * m_BitsPerSample;
  iBytesPerSecond = m_Bitrate / 8;
}

PCMCodec::~PCMCodec()
{
  DeInit();
}

bool PCMCodec::Init(const CStdString &strFile, unsigned int filecache)
{
  m_file.Close();
  if (!m_file.Open(strFile, READ_CACHED))
  {
    CLog::Log(LOGERROR, "PCMCodec::Init - Failed to open file");
    return false;
  }
  int64_t length = m_file.GetLength();
  m_TotalTime = (int)(((float)length / iBytesPerSecond) * 1000);
  m_file.Seek(0, SEEK_SET);
  return true;
}

void PCMCodec::DeInit()
{
  m_file.Close();
}

__int64 PCMCodec::Seek(__int64 iSeekTime)
{
  m_file.Seek((iSeekTime / 1000) * iBytesPerSecond);
  return iSeekTime;
}

int PCMCodec::ReadPCM(BYTE *pBuffer, int size, int *actualsize)
{
  *actualsize = 0;
  int iAmountRead = m_file.Read(pBuffer, size);
  if (iAmountRead > 0)
  {
    *actualsize = iAmountRead;
    return READ_SUCCESS;
  }
  return READ_ERROR;
}

bool PCMCodec::CanInit()
{
  return true;
}

void PCMCodec::SetMimeParams(const CStdString& strMimeParams)
{
  if (strMimeParams.Find("rate=48000") > 0)
    m_SampleRate = 48000;
  if (strMimeParams.Find("channels=1") > 0)
    m_Channels = 1;

  m_Bitrate = m_SampleRate * m_Channels * m_BitsPerSample;
  iBytesPerSecond = m_Bitrate / 8;
}




+++++ CodecFactory.cpp +++++

ICodec* CodecFactory::CreateCodec(const CStdString& strFileType)
{
  if (strFileType.Equals("mp3") || strFileType.Equals("mp2"))
    return new MP3Codec();

<pcm_codec_code>
  else if (strFileType.Equals("pcm"))
    return new PCMCodec();
</pcm_codec_code>

  ...


ICodec* CodecFactory::CreateCodecDemux(const CStdString& strFile, const CStdString& strContent, unsigned int filecache)
{
  CURL urlFile(strFile);
  if(strContent.Equals("audio/mpeg") || strContent.Equals("audio/mp3") )
    return new MP3Codec();

<pcm_codec_code>
  else if (strContent.Find("audio/L16") == 0)
  {
    PCMCodec *pcm_codec = new PCMCodec();
    if (pcm_codec)
    {
      pcm_codec->SetMimeParams(strContent);
      return pcm_codec;
    }
  }
</pcm_codec_code>

  ...
Reply
#6
cool. can you please do it properly as a pull request on github or a patch on trac? will get lost in here... also those hardcoded values in the constructor should be params read from the mime-type no?
Reply
#7
spiff Wrote:cool. can you please do it properly as a pull request on github or a patch on trac?
Sure. I think I need to create a new .h and .cpp file on the repo; I can't just fork and edit one of the existing ones; => can you explain how I should do that?

Quote:also those hardcoded values in the constructor should be params read from the mime-type no?
Indeed. But I had to stay with the argument template for the methods in the parent class, and so I couldn't pass in the extra params in the Init() method. So, in the meantime I added another SetMimeParams() method to my code...

--
AndrewFG
Reply
#8
1. Fork xbmc/xbmc repo to your own github repo.
2. Add your changes, commit locally (git add the new files + modified files followed by git commit).
3. Push your changes to your fork.
4. Do a pull req.

Alternatively, just do number 2 locally, and then git format-patch HEAD~k to grab the top k commits and attach to a trac report.

Cheers,
Jonathan
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#9
jmarshall Wrote:Do a pull req.

Ok done. https://github.com/xbmc/xbmc/pull/251

--
AndrewFG
Reply
#10
andrewfg Wrote:Ok done. https://github.com/xbmc/xbmc/pull/251
Can anyone please attend to this puill request? It is ready...
Reply
#11
Patience Smile My PR from april is still on the oven. the 8 commits have since been broken out to separate pull requests, some of which were accepted in a day, others a few weeks, and some are still awaiting more review. Merging on git is a long, slow process. It is fortunate that we have git because then it would be a Trac - patch - Trac comment - patch a patch - debug log - debug log *with* debugging - Trac Comment ad inifitum, as in the psat.

Git is a timely process, so some impatience is normal. Check out davilla's comments, fix his and wait a day to a week, someone else will review and then wait another week to make sure everyone's had time to finish reviewing. In the land of the free and the open source, time is undermined by what is best for the sofware.

Good luck!
RetroPlayer releases: https://github.com/garbear/xbmc/releases

Donations: eigendude.eth
Reply
#12
Ok. I'm cool...
Reply

Logout Mark Read Team Forum Stats Members Help
Codec for PCM streams0