osx で fuppes を使ってみる [Mac]
fuppes はここで配布されている UPnP AV Media Server で、最近はDLNAにも対応したらしい。
このサーバには、iTunes ライブラリの xml ファイルを読んでそのままDLNA機器へ見せてくれるという便利機能があるので、最近導入したDLNA対応テレビ(v1.0)で使うべく、設定しみたのでそのメモ。
導入先は10.5.1のMacBook。
iTunes は最新。
コンテンツは MP3 と AAC が半々くらい。
このソフトはソースで配布しているので、まずは ここの指示にしたがって、Xcode やmacportを導入。
この時、autoconf などもmacport で入れてやらないとはまるので注意。
あと、トランスコード用に、libid3tag, libfaad2, libmad が必要なので忘れずに macport でインストールする。libfaad2 をビルドした際に作成される mp4ff ライブラリと関連ヘッダーファイルを /opt/local 以下へコピーしておく。
次に fuppes を subversion でチェックアウトしてビルドする。
パッチ作成時にチェックアウトしたリビジョンは r588。
ビルド前に添付のパッチを適用する。
このパッチでは、
- config ファイルの設定にかかわらず DLNA サーバ機能を常に有効化。(なぜか有効にならないので)
- DLNAでのタイプが正しくならないので無理矢理 PCM に設定。
- macport では mp4ff がダイナミックライブラリ化されないので、スタティックリンクする。
その他いくつか修正を行う。
で、インストール後、動かす前に
DYLD_FALLBACK_LIBRARY_PATH
にでも、/opt/local/lib を追加しておく。
そして、こんな感じでトランスコードの設定を追加しておく。
<file ext="m4a"> <type>AUDIO_ITEM</type> <mime_type>audio/m4a</mime_type> <transcode enabled="true"> <ext>lpcm</ext> <mime_type>audio/L16</mime_type> <dlna>LPCM</dlna> <http_encoding>stream</http_encoding> <decoder>faad</decoder> <encoder>pcm</encoder> </transcode> </file> <file ext="mp3"> <type>AUDIO_ITEM</type> <mime_type>audio/mpeg</mime_type> <dlna>MP3</dlna> <transcode enabled="true"> <ext>lpcm</ext> <mime_type>audio/L16</mime_type> <dlna>LPCM</dlna> <http_encoding>stream</http_encoding> <decoder>mad</decoder> <encoder>pcm</encoder> </transcode> </file>
これでだいたい MP3(MPEG1 L3のみ)と、MP4 コンテナの AAC-LC がテレビで再生できるようになるが、まだ再生長がおかしいものがあるようだ。もうちょっと修正が必要そう。
以下、パッチ。
Index: src/lib/DeviceSettings/DeviceSettings.cpp
===================================================================
--- src/lib/DeviceSettings/DeviceSettings.cpp (リビジョン 588)
+++ src/lib/DeviceSettings/DeviceSettings.cpp (作業コピー)
@@ -384,7 +384,8 @@
m_MediaServerSettings.SerialNumber = "0123456789";
m_MediaServerSettings.UseSerialNumber = true;
m_MediaServerSettings.UseUPC = false;
- m_MediaServerSettings.UseDLNA = false;
+ m_MediaServerSettings.UseDLNA = true;
+// m_MediaServerSettings.UseDLNA = false;
m_MediaServerSettings.UseURLBase = true;
m_MediaServerSettings.UseXMSMediaReceiverRegistrar = false;
@@ -422,7 +423,8 @@
m_MediaServerSettings.UseSerialNumber = pSettings->MediaServerSettings()->UseSerialNumber;
m_MediaServerSettings.UPC = pSettings->MediaServerSettings()->UPC;
m_MediaServerSettings.UseUPC = pSettings->MediaServerSettings()->UseUPC;
- m_MediaServerSettings.UseDLNA = pSettings->MediaServerSettings()->UseDLNA;
+ //m_MediaServerSettings.UseDLNA = pSettings->MediaServerSettings()->UseDLNA;
+ m_MediaServerSettings.UseDLNA = true;
m_MediaServerSettings.UseURLBase = pSettings->MediaServerSettings()->UseURLBase;
m_MediaServerSettings.UseXMSMediaReceiverRegistrar = pSettings->MediaServerSettings()->UseXMSMediaReceiverRegis
trar;
Index: src/lib/ContentDirectory/ContentDirectory.cpp
===================================================================
--- src/lib/ContentDirectory/ContentDirectory.cpp (リビジョン 588)
+++ src/lib/ContentDirectory/ContentDirectory.cpp (作業コピー)
@@ -1150,7 +1150,8 @@
if(!p_sProfileId.empty()) {
sprintf(dlna_info, "%s=%d;%s=%d;%s=%.2x;%s=%s;%s=%.8x%.24x",
"DLNA.ORG_PS", DLNA_ORG_PLAY_SPEED_NORMAL, "DLNA.ORG_CI", ci,
- "DLNA.ORG_OP", op, "DLNA.ORG_PN", p_sProfileId.c_str(),
+// "DLNA.ORG_OP", op, "DLNA.ORG_PN", p_sProfileId.c_str(),
+ "DLNA.ORG_OP", op, "DLNA.ORG_PN", "LPCM",
"DLNA.ORG_FLAGS", flags, 0);
}
else {
Index: src/lib/Transcoding/TranscodingCache.cpp
===================================================================
--- src/lib/Transcoding/TranscodingCache.cpp (リビジョン 588)
+++ src/lib/Transcoding/TranscodingCache.cpp (作業コピー)
@@ -346,6 +346,7 @@
{
// encode
nEncRet = pCacheObj->m_pAudioEncoder->EncodeInterleaved(pCacheObj->m_pPcmOut, samplesRead, nBytesConsumed);
+ //cout << "encintl samplesRead : " << samplesRead << " nBytesConsumed: " <MadLibName().empty()) {
@@ -157,27 +158,22 @@
m_MadFrameInit(&m_Frame);
m_MadSynthInit(&m_Synth);
-
- /*int nBytesRead = fread(InputBuffer, INPUT_BUFFER_SIZE, 1, m_pFile);
-
- mad_stream_buffer(&m_Stream,InputBuffer,INPUT_BUFFER_SIZE);*/
-
struct mad_header Header;
mad_header_init(&Header);
+ //int nBytesRead = fread(InputBuffer, INPUT_BUFFER_SIZE, 1, m_pFile);
+ //mad_stream_buffer(&m_Stream,InputBuffer,INPUT_BUFFER_SIZE);
//mad_header_decode(&Header, &m_Stream);
- /*cout << Header.bitrate << endl;
- cout << Header.samplerate << endl;
- fflush(stdout);*/
-
-
//struct mad_stream stream;
//struct mad_header header;
//unsigned char buffer[INPUT_BUFFER_SIZE];
+
unsigned int nBuffLen = 0;
+
//mad_stream_init (&stream);
//mad_header_init (&header);
+
struct stats_t stats;
m_nNumFrames = 0;
@@ -193,13 +189,16 @@
}
mad_stream_buffer(&m_Stream, InputBuffer, nBuffLen);
+
while(true) {
if(mad_header_decode (&Header, &m_Stream) == -1) {
- if(!MAD_RECOVERABLE(m_Stream.error))
+ if(!MAD_RECOVERABLE(m_Stream.error)) {
break;
+ }
if (m_Stream.error == MAD_ERROR_LOSTSYNC) {
/* ignore LOSTSYNC due to ID3 tags */
- int tagsize = 1; //id3_tag_query (m_Stream.this_frame, m_Stream.bufend - m_Stream.this_frame);
+ //int tagsize = 1; //id3_tag_query (m_Stream.this_frame, m_Stream.bufend - m_Stream.this_frame);
+ int tagsize = id3_tag_query (m_Stream.this_frame, m_Stream.bufend - m_Stream.this_frame);
if (tagsize > 0) {
mad_stream_skip (&m_Stream, tagsize);
continue;
@@ -327,8 +326,10 @@
/* Right channel. If the decoded stream is monophonic then
* the right output channel is the same as the left one.
*/
+
if(MAD_NCHANNELS(&m_Frame.header)==2)
Sample=MadFixedToSshort(m_Synth.pcm.samples[1][i]);
+
*(m_OutputPtr++)=Sample>>8;
*(m_OutputPtr++)=Sample&0xff;
@@ -339,13 +340,13 @@
/* Flush the output buffer if it is full. */
if(m_OutputPtr == m_OutputBufferEnd) {
m_nSynthPos = i + 1;
- cout << "out buffer full " << *p_nBytesRead << " - samples : " << nSamples << "
pos " << m_nSynthPos << endl;
+ //cout << "out buffer full " << *p_nBytesRead << " - samples : " << nSamples << " pos " << m_nSynthPos << end
l;
return nSamples;
}
}
- cout << "no samples left " << nSamples << " of " << m_Synth.pcm.length << " - pos " << m_nSynthPos << endl;
- cout << "out buffer: " << *p_nBytesRead << " of " << p_nBufferSize << endl;
+ //cout << "no samples left " << nSamples << " of " << m_Synth.pcm.length << " - pos " << m_nSynthPos << endl;
+ //cout << "out buffer: " << *p_nBytesRead << " of " << p_nBufferSize << endl;
m_nSynthPos = -1;
return nSamples;
}
@@ -357,23 +358,23 @@
// frames left
if(m_Stream.next_frame!=NULL) {
- cout << "frames left" << endl;
- fflush(stdout);
+ //cout << "frames left" << endl;
+ //fflush(stdout);
Remaining = m_Stream.bufend - m_Stream.next_frame;
memmove(m_InputBuffer, m_Stream.next_frame, Remaining);
ReadStart = m_InputBuffer + Remaining;
ReadSize = INPUT_BUFFER_SIZE - Remaining;
}
else {
- cout << "buffer is empty" << endl;
- fflush(stdout);
+ //cout << "buffer is empty" << endl;
+ //fflush(stdout);
ReadSize = INPUT_BUFFER_SIZE;
ReadStart = m_InputBuffer;
Remaining = 0;
}
// fill buffer
- cout << "read " << ReadSize << " bytes - remaining: " << Remaining << endl;
+ //cout << "read " << ReadSize << " bytes - remaining: " << Remaining << endl;
fflush(stdout);
ReadSize = fread(ReadStart, 1, ReadSize, m_pFile);
@@ -397,11 +398,11 @@
} // read file and fill buffer
// decode
- /*cout << "decode ";
- fflush(stdout);*/
+ //cout << "decode ";
+ //fflush(stdout);
int nDec = mad_frame_decode(&m_Frame, &m_Stream);
- /*cout << nDec << endl;
- fflush(stdout);*/
+ //cout << nDec << endl;
+ //fflush(stdout);
if(nDec > 0) {
if(MAD_RECOVERABLE(m_Stream.error)) {
Index: src/lib/Transcoding/FaadWrapper.cpp
===================================================================
--- src/lib/Transcoding/FaadWrapper.cpp (リビジョン 588)
+++ src/lib/Transcoding/FaadWrapper.cpp (作業コピー)
@@ -34,6 +34,8 @@
*/
#include "FaadWrapper.h"
+#include "/opt/local/include/faad.h"
+#include "/opt/local/include/mp4ff.h"
#ifndef DISABLE_TRANSCODING
#ifdef HAVE_FAAD
@@ -209,7 +211,7 @@
};
#ifdef HAVE_MP4FF_H
-int CFaadWrapper::DecodeMP4file(char* p_PcmOut)
+int CFaadWrapper::DecodeMP4file(char* p_PcmOut, int* p_nBytesRead)
{
void *sample_buffer;
unsigned char *buffer;
@@ -231,6 +233,7 @@
dur = m_mp4ff_get_sample_duration(infile, track, sampleId);
rc = m_mp4ff_read_sample(infile, track, sampleId, &buffer, &buffer_size);
+fprintf(stderr, "sampleId %d\n", sampleId);
if (rc == 0) {
fprintf(stderr, "Reading from MP4 file failed.\n");
return -1;
@@ -266,26 +269,32 @@
first_time = false;
}
- if (sample_count > 0)
- initial = 0;
- if ((frameInfo.error == 0) && (sample_count > 0)) {
+ if ((frameInfo.error == 0) && (sample_count > 0) && initial == 0) {
write_audio_16bit(p_PcmOut, sample_buffer, sample_count);
}
+ if (sample_count > 0) {
+ if (initial != 0) {
+ frameInfo.samples = 0;
+ initial--;
+ }
+}
+
if (frameInfo.error > 0) {
fprintf(stderr, "Warning: %s\n",
m_faacDecGetErrorMessage(frameInfo.error));
}
- } while (frameInfo.samples == 0 && initial);
-
sampleId++;
+ } while (frameInfo.samples == 0 && initial);
- if(frameInfo.samples > 0)
+ if(frameInfo.samples >= 0) {
+ *p_nBytesRead = frameInfo.samples * 2;
+ //fprintf(stderr, "frameInfo samples %d\n", frameInfo.samples);
return frameInfo.samples / 2;
- else
+ } else
return -1;
}
#endif // HAVE_MP4FF_H
@@ -332,7 +341,7 @@
#ifdef WIN32
std::string sLibName = "libfaad-0.dll";
#else
- std::string sLibName = "libfaad.so.0";
+ std::string sLibName = "libfaad.dylib";
#endif
if(!CSharedConfig::Shared()->FaadLibName().empty()) {
@@ -340,6 +349,7 @@
}
CSharedLog::Shared()->Log(L_EXT, "try opening " + sLibName, __FILE__, __LINE__);
+
m_LibHandle = FuppesLoadLibrary(sLibName);
if(!m_LibHandle) {
CSharedLog::Shared()->Log(L_EXT, "cannot open library " + sLibName, __FILE__, __LINE__);
@@ -347,52 +357,62 @@
return false;
}
- m_faacDecOpen = (faacDecOpen_t)FuppesGetProcAddress(m_LibHandle, "faacDecOpen");
+ //m_faacDecOpen = (faacDecOpen_t)FuppesGetProcAddress(m_LibHandle, "faacDecOpen");
+ m_faacDecOpen = faacDecOpen;
if(!m_faacDecOpen) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'faacDecOpen'", __FILE__, __LINE__);
return false;
}
- m_faacDecGetErrorMessage = (faacDecGetErrorMessage_t)FuppesGetProcAddress(m_LibHandle, "faacDecGetErrorMessage");
+ //m_faacDecGetErrorMessage = (faacDecGetErrorMessage_t)FuppesGetProcAddress(m_LibHandle, "faacDecGetErrorMessage");
+ m_faacDecGetErrorMessage = faacDecGetErrorMessage;
if(!m_faacDecGetErrorMessage) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'faacDecGetErrorMessage'", __FILE__, __LINE__);
return false;
}
- m_faacDecGetCurrentConfiguration = (faacDecGetCurrentConfiguration_t)FuppesGetProcAddress(m_LibHandle, "faacDecGetCu
rrentConfiguration");
+ //m_faacDecGetCurrentConfiguration = (faacDecGetCurrentConfiguration_t)FuppesGetProcAddress(m_LibHandle, "faacDecGet
CurrentConfiguration");
+ m_faacDecGetCurrentConfiguration = faacDecGetCurrentConfiguration;
if(!m_faacDecGetCurrentConfiguration) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'faacDecGetCurrentConfiguration'", __FILE__, __LINE__);
}
- m_faacDecSetConfiguration = (faacDecSetConfiguration_t)FuppesGetProcAddress(m_LibHandle, "faacDecSetConfiguration");
+ //m_faacDecSetConfiguration = (faacDecSetConfiguration_t)FuppesGetProcAddress(m_LibHandle, "faacDecSetConfiguration"
);
+ m_faacDecSetConfiguration = faacDecSetConfiguration;
if(!m_faacDecSetConfiguration) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'faacDecSetConfiguration'", __FILE__, __LINE__);
}
- m_faacDecInit = (faacDecInit_t)FuppesGetProcAddress(m_LibHandle, "faacDecInit");
+ //m_faacDecInit = (faacDecInit_t)FuppesGetProcAddress(m_LibHandle, "faacDecInit");
+ m_faacDecInit = faacDecInit;
if(!m_faacDecInit) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'faacDecInit'", __FILE__, __LINE__);
}
- m_faacDecInit2 = (faacDecInit2_t)FuppesGetProcAddress(m_LibHandle, "faacDecInit2");
+ //m_faacDecInit2 = (faacDecInit2_t)FuppesGetProcAddress(m_LibHandle, "faacDecInit2");
+ m_faacDecInit2 = faacDecInit2;
if(!m_faacDecInit2) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'faacDecInit2'", __FILE__, __LINE__);
return false;
}
- m_faacDecDecode = (faacDecDecode_t)FuppesGetProcAddress(m_LibHandle, "faacDecDecode");
+ //m_faacDecDecode = (faacDecDecode_t)FuppesGetProcAddress(m_LibHandle, "faacDecDecode");
+ m_faacDecDecode = faacDecDecode;
if(!m_faacDecDecode) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'faacDecDecode'", __FILE__, __LINE__);
return false;
}
- m_faacDecClose = (faacDecClose_t)FuppesGetProcAddress(m_LibHandle, "faacDecClose");
+ //m_faacDecClose = (faacDecClose_t)FuppesGetProcAddress(m_LibHandle, "faacDecClose");
+ m_faacDecClose = faacDecClose;
if(!m_faacDecClose) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'faacDecClose'", __FILE__, __LINE__);
return false;
}
- m_AudioSpecificConfig = (AudioSpecificConfig_t)FuppesGetProcAddress(m_LibHandle, "AudioSpecificConfig");
+ //m_AudioSpecificConfig = (AudioSpecificConfig_t)FuppesGetProcAddress(m_LibHandle, "AudioSpecificConfig");
+ m_AudioSpecificConfig = AudioSpecificConfig;
+
if(!m_AudioSpecificConfig) {
m_AudioSpecificConfig = (AudioSpecificConfig_t)FuppesGetProcAddress(m_LibHandle, "faacDecAudioSpecificC
onfig");
if(!m_AudioSpecificConfig) {
@@ -415,57 +435,67 @@
}
CSharedLog::Shared()->Log(L_EXT, "try opening " + sLibName, __FILE__, __LINE__);
+/*
m_mp4ffLibHandle = FuppesLoadLibrary(sLibName);
if(!m_mp4ffLibHandle) {
CSharedLog::Shared()->Log(L_EXT, "cannot open library " + sLibName, __FILE__, __LINE__);
printf("[WARNING :: AACDecoder] cannot open library %s\n", sLibName.c_str());
return false;
}
+*/
- m_mp4ff_read_sample = (mp4ff_read_sample_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_read_sample");
+ //m_mp4ff_read_sample = (mp4ff_read_sample_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_read_sample");
+ m_mp4ff_read_sample = mp4ff_read_sample;
if(!m_mp4ff_read_sample) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'mp4ff_read_sample'", __FILE__, __LINE__);
return false;
}
- m_mp4ff_time_scale = (mp4ff_time_scale_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_time_scale");
+ //m_mp4ff_time_scale = (mp4ff_time_scale_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_time_scale");
+ m_mp4ff_time_scale = mp4ff_time_scale;
if(!m_mp4ff_time_scale) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'mp4ff_time_scale'", __FILE__, __LINE__);
return false;
}
- m_mp4ff_num_samples = (mp4ff_num_samples_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_num_samples");
+ //m_mp4ff_num_samples = (mp4ff_num_samples_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_num_samples");
+ m_mp4ff_num_samples = mp4ff_num_samples;
if(!m_mp4ff_num_samples) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'mp4ff_num_samples'", __FILE__, __LINE__);
return false;
}
- m_mp4ff_open_read = (mp4ff_open_read_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_open_read");
+ //m_mp4ff_open_read = (mp4ff_open_read_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_open_read");
+ m_mp4ff_open_read = mp4ff_open_read;
if(!m_mp4ff_open_read) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'mp4ff_open_read'", __FILE__, __LINE__);
return false;
}
- m_mp4ff_close = (mp4ff_close_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_close");
+ //m_mp4ff_close = (mp4ff_close_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_close");
+ m_mp4ff_close = mp4ff_close;
if(!m_mp4ff_close) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'mp4ff_close'", __FILE__, __LINE__);
return false;
}
- m_mp4ff_get_decoder_config = (mp4ff_get_decoder_config_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_get_decoder_c
onfig");
+ //m_mp4ff_get_decoder_config = (mp4ff_get_decoder_config_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_get_decoder
_config");
+ m_mp4ff_get_decoder_config = mp4ff_get_decoder_config;
if(!m_mp4ff_get_decoder_config) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'mp4ff_get_decoder_config'", __FILE__, __LINE__);
return false;
}
- m_mp4ff_total_tracks = (mp4ff_total_tracks_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_total_tracks");
+ //jm_mp4ff_total_tracks = (mp4ff_total_tracks_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_total_tracks");
+ m_mp4ff_total_tracks = mp4ff_total_tracks;
if(!m_mp4ff_total_tracks) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'mp4ff_total_tracks'", __FILE__, __LINE__);
return false;
}
- m_mp4ff_get_sample_duration = (mp4ff_get_sample_duration_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_get_sample_
duration");
+ //m_mp4ff_get_sample_duration = (mp4ff_get_sample_duration_t)FuppesGetProcAddress(m_mp4ffLibHandle, "mp4ff_get_sampl
e_duration");
+ m_mp4ff_get_sample_duration = mp4ff_get_sample_duration;
if(!m_mp4ff_get_sample_duration) {
CSharedLog::Shared()->Log(L_EXT, "cannot load symbol 'mp4ff_get_sample_duration'", __FILE__, __LINE__);
return false;
@@ -529,7 +559,8 @@
{
if(m_bIsMp4) {
#ifdef HAVE_MP4FF_H
- return DecodeMP4file(p_PcmOut);
+// *p_nBytesRead = 1024 * 2 * 2;
+ return DecodeMP4file(p_PcmOut, p_nBytesRead);
#else
return -1;
#endif // HAVE_MP4FF_H
@@ -657,7 +688,7 @@
// for gapless decoding
useAacLength = 1;
- initial = 1;
+ initial = 3;
// initialise the callback structure
コメント 0