出发点:Android电视棒实现DLNA功能采用JAVA版本的cyberlink的话,缺点明显,SSDP协议设备发现有延时(有时还发现不了设备)体验差,基于Linux电视棒可以控制硬件成本在100元以下,而且c语言实现的cyberlink DLNA协议栈不存在设备发现不了的情况,本文记录记录linux下实现dlna碰到的一揽子问题
1. DLNA的DMR方案
方案1: MediaGateForCC (http://www.cybergarage.org/twiki/bin/view/Main/MediaGateForCC) 交叉编译,基于gstreamer实现播放器
Cyberlink协议栈需要依赖xml库, 可以选择xerces和libxml2, xerces是apatch提供的一个比较庞大的xml解析库,嵌入式设备不考虑。
1) 编译libxml2
./configure --prefix=/home/work/mylib --host=mips-linux-gnu --build=i686 --target=mips-linux-gnu CC=mips-linux-gnu-gcc -EL CFLAGS=-I/home/work/mylib/include LDFLAGS=-L/home/work/mylib/lib
2)编译MediaGateForCC
./configure --prefix=/home/work/mylib --host=mips-linux-gnu --build=i686 --target=mips-linux-gnu CC=mips-linux-gnu-gcc -EL --enable-libxml2 CFLAGS=-I/home/work/mylib/include CPPFLAGS=-I/home/work/mylib/include LDFLAGS=-L/home/work/mylib/lib
错误1:LibXml2Parser.cpp中Node *newChildNode = convertToCLinkFormat( doc, child, depth 1)改成Node *newChildNode = convertToCLinkFormat( doc, child, depth );
错误2:ControlPoint.cpp中Device **dev = new (Device(*[devCnt])); 改成 Device **dev = new Device* [devCnt];
编译成功
3) CyberLink中没有实现Media Renderer的AVTransport和RenderingControl服务,以下是补充的AVTransport..h和RenderingControl.h
class AVT : public ActionListener, public QueryListener { CyberUtil::Mutex mutex; int maxConnectionID; //////////////////////////////////////////////// // Constants //////////////////////////////////////////////// public: static const char *DESCRIPTION; static const char *SERVICE_TYPE; static const char * TRANSPORTSTATE ; static const char * TRANSPORTSTATUS ; static const char * PLAYBACKSTORAGEMEDIUM; static const char * RECORDSTORAGEMEDIUM; static const char * POSSIBLEPLAYBACKSTORAGEMEDIA; static const char * POSSIBLERECORDSTORAGEMEDIA; static const char * CURRENTPLAYMODE ; static const char * TRANSPORTPLAYSPEED; static const char * RECORDMEDIUMWRITESTATUS ; static const char * CURRENTRECORDQUALITYMODE ; static const char * POSSIBLERECORDQUALITYMODES; static const char * NUMBEROFTRACKS; static const char * CURRENTTRACK; static const char * CURRENTTRACKDURATION; static const char * CURRENTMEDIADURATION; static const char * CURRENTTRACKMETADATA; static const char * CURRENTTRACKURI; static const char * AVTRANSPORTURI; static const char * AVTRANSPORTURIMETADATA ; static const char * NEXTAVTRANSPORTURI; static const char * NEXTAVTRANSPORTURIMETADATA; static const char * RELATIVETIMEPOSITION; static const char * ABSOLUTETIMEPOSITION; static const char * RELATIVECOUNTERPOSITION ; static const char * ABSOLUTECOUNTERPOSITION ; static const char * CURRENTTRANSPORTACTIONS; static const char * LASTCHANGE; static const char * SETAVTRANSPORTURI; static const char * INSTANCEID; static const char * CURRENTURI; static const char * CURRENTURIMETADATA; static const char * SETNEXTAVTRANSPORTURI; static const char * NEXTURI; static const char * NEXTURIMETADATA ; static const char * GETMEDIAINFO; static const char * NRTRACKS; static const char * MEDIADURATION; static const char * PLAYMEDIUM ; static const char * RECORDMEDIUM ; static const char * WRITESTATUS ; static const char * GETTRANSPORTINFO ; static const char * CURRENTTRANSPORTSTATE; static const char * CURRENTTRANSPORTSTATUS ; static const char * CURRENTSPEED ; static const char * GETPOSITIONINFO; static const char * TRACK; static const char * TRACKDURATION; static const char * TRACKMETADATA ; static const char * TRACKURI ; static const char * RELTIME; static const char * ABSTIME; static const char * RELCOUNT; static const char * ABSCOUNT; static const char * GETDEVICECAPABILITIES; static const char * PLAYMEDIA ; static const char * RECMEDIA ; static const char * RECQUALITYMODES; static const char * GETTRANSPORTSETTINGS; static const char * PLAYMODE ; static const char * RECQUALITYMODE ; static const char * STOP; static const char * PLAY; static const char * SPEED ; static const char * PAUSE; static const char * RECORD ; static const char * SEEK ; static const char * UNIT; static const char * TARGET ; static const char * NEXT ; static const char * PREVIOUS ; static const char * SETPLAYMODE ; static const char * NEWPLAYMODE ; static const char * SETRECORDQUALITYMODE ; static const char * NEWRECORDQUALITYMODE ; static const char * GETCURRENTTRANSPORTACTIONS; static const char * ACTIONS; static const char * STOPPED ; static const char * PLAYING ; static const char * OK; static const char * ERROR_OCCURRED ; static const char * NORMAL ; static const char * TRACK_NR ; //////////////////////////////////////////////// // Constructor //////////////////////////////////////////////// public: AVT(); virtual ~AVT(); public: void lock() { mutex.lock(); } void unlock() { mutex.unlock(); } //////////////////////////////////////////////// // ConnectionID //////////////////////////////////////////////// //////////////////////////////////////////////// // ActionListener //////////////////////////////////////////////// public: bool actionControlReceived(Action *action); public: bool queryControlReceived(StateVariable *stateVar); };
RenderingControl服务类
class RC : public ActionListener, public QueryListener { CyberUtil::Mutex mutex; int maxConnectionID; //////////////////////////////////////////////// // Constants //////////////////////////////////////////////// public: static const char *DESCRIPTION; static const char *SERVICE_TYPE; static const char *PRESETNAMELIST ; static const char *LASTCHANGE ; static const char *BRIGHTNESS; static const char *CONTRAST ; static const char *SHARPNESS ; static const char *REDVIDEOGAIN; static const char *GREENVIDEOGAIN ; static const char *BLUEVIDEOGAIN ; static const char *REDVIDEOBLACKLEVEL; static const char *GREENVIDEOBLACKLEVEL ; static const char *BLUEVIDEOBLACKLEVEL ; static const char *COLORTEMPERATURE ; static const char *HORIZONTALKEYSTONE ; static const char *VERTICALKEYSTONE ; static const char *MUTE ; static const char *VOLUME ; static const char *VOLUMEDB ; static const char *LOUDNESS ; static const char *LISTPRESETS; static const char *INSTANCEID ; static const char *CURRENTPRESETNAMELIST; static const char *SELECTPRESET; static const char *PRESETNAME; static const char *GETBRIGHTNESS; static const char *CURRENTBRIGHTNESS ; static const char *SETBRIGHTNESS; static const char *DESIREDBRIGHTNESS; static const char *GETCONTRAST; static const char *CURRENTCONTRAST; static const char *SETCONTRAST; static const char *DESIREDCONTRAST; static const char *GETSHARPNESS; static const char *CURRENTSHARPNESS; static const char *SETSHARPNESS; static const char *DESIREDSHARPNESS; static const char *GETREDVIDEOGAIN; static const char *CURRENTREDVIDEOGAIN; static const char *SETREDVIDEOGAIN; static const char *DESIREDREDVIDEOGAIN ; static const char *GETGREENVIDEOGAIN; static const char *CURRENTGREENVIDEOGAIN; static const char *SETGREENVIDEOGAIN ; static const char *DESIREDGREENVIDEOGAIN ; static const char *GETBLUEVIDEOGAIN ; static const char *CURRENTBLUEVIDEOGAIN ; static const char *SETBLUEVIDEOGAIN; static const char *DESIREDBLUEVIDEOGAIN ; static const char *GETREDVIDEOBLACKLEVEL ; static const char *CURRENTREDVIDEOBLACKLEVEL ; static const char *SETREDVIDEOBLACKLEVEL; static const char *DESIREDREDVIDEOBLACKLEVEL; static const char *GETGREENVIDEOBLACKLEVEL; static const char *CURRENTGREENVIDEOBLACKLEVEL; static const char *SETGREENVIDEOBLACKLEVEL; static const char *DESIREDGREENVIDEOBLACKLEVEL; static const char *GETBLUEVIDEOBLACKLEVEL; static const char *CURRENTBLUEVIDEOBLACKLEVEL; static const char *SETBLUEVIDEOBLACKLEVEL; static const char *DESIREDBLUEVIDEOBLACKLEVEL; static const char *GETCOLORTEMPERATURE ; static const char *CURRENTCOLORTEMPERATURE; static const char *SETCOLORTEMPERATURE; static const char *DESIREDCOLORTEMPERATURE; static const char *GETHORIZONTALKEYSTONE; static const char *CURRENTHORIZONTALKEYSTONE; static const char *SETHORIZONTALKEYSTONE; static const char *DESIREDHORIZONTALKEYSTONE; static const char *GETVERTICALKEYSTONE; static const char *CURRENTVERTICALKEYSTONE; static const char *SETVERTICALKEYSTONE; static const char *DESIREDVERTICALKEYSTONE; static const char *GETMUTE ; static const char *CHANNEL; static const char *CURRENTMUTE ; static const char *SETMUTE; static const char *DESIREDMUTE; static const char *GETVOLUME; static const char *CURRENTVOLUME ; static const char *SETVOLUME ; static const char *DESIREDVOLUME ; static const char *GETVOLUMEDB ; static const char *SETVOLUMEDB; static const char *GETVOLUMEDBRANGE ; static const char *MINVALUE; static const char *MAXVALUE; static const char *GETLOUDNESS ; static const char *CURRENTLOUDNESS; static const char *SETLOUDNESS ; static const char *DESIREDLOUDNESS; static const char *MASTER ; static const char *FACTORYDEFAULTS ; public: RC(); virtual ~RC(); public: void lock() { mutex.lock(); } void unlock() { mutex.unlock(); } //////////////////////////////////////////////// // ConnectionID //////////////////////////////////////////////// public: bool actionControlReceived(Action *action); public: bool queryControlReceived(StateVariable *stateVar); };
4)MediaRender的实现
MediaRender主要是实现ConnectionManager、AVTransport和RenderingControl服务
class MP : public Device { CM *conMan; AVT *avTrans; RC *renderCon; //////////////////////////////////////////////// // Constants //////////////////////////////////////////////// public: static const char *DEVICE_TYPE; static const int DEFAULT_HTTP_PORT; static const char *DESCRIPTION; //////////////////////////////////////////////// // Constructor //////////////////////////////////////////////// public: MP(); ~MP(); //////////////////////////////////////////////// // setName //////////////////////////////////////////////// public: void setName(const char *name) { setFriendlyName(name); } const char *getName() { getFriendlyName(); } //////////////////////////////////////////////// // Memeber //////////////////////////////////////////////// public: CM *getConnectionManager() { return conMan; } AVT *getAVTransport() { return avTrans; } RC *getRenderingControl() { return renderCon; } //////////////////////////////////////////////// // ContentDirectory //////////////////////////////////////////////// public: void setInterfaceAddress(const char *ifaddr) { CyberNet::SetHostInterface(ifaddr); } const char *getInterfaceAddress() { return CyberNet::GetHostInterface(); } //////////////////////////////////////////////// // HttpRequestListner (Overridded) //////////////////////////////////////////////// public: void httpRequestRecieved(CyberHTTP::HTTPRequest *httpReq); //////////////////////////////////////////////// // start/stop (Overided) //////////////////////////////////////////////// public: bool start() { Device::start(); return true; } bool stop() { Device::stop(); return true; } };
MP::MP() : Device() { // Device Configuration loadDescription(MP::DESCRIPTION); // Netwroking initialization UPnP::SetEnable(UPnP::USE_ONLY_IPV4_ADDR); string firstIf; GetHostAddress(0, firstIf); setInterfaceAddress(firstIf.c_str()); setHTTPPort(DEFAULT_HTTP_PORT); // Servce Configuration conMan = new CM(); Service *servConMan = getService(CM::SERVICE_TYPE); servConMan->loadSCPD(CM::DESCRIPTION); servConMan->setActionListener(getConnectionManager()); servConMan->setQueryListener(getConnectionManager()); avTrans= new AVT(); Service *servAvt = getService(AVT::SERVICE_TYPE); servAvt->loadSCPD(AVT::DESCRIPTION); servAvt->setActionListener(getAVTransport()); servAvt->setQueryListener(getAVTransport()); renderCon= new RC(); Service *servRC = getService(RC::SERVICE_TYPE); servRC->loadSCPD(RC::DESCRIPTION); servRC->setActionListener(getRenderingControl()); servRC->setQueryListener(getRenderingControl()); }
int main(int argc, char* argv[]) { MP mplayer; Debug::on(); PrintMessage(); //MediaPlayer mplayer; mplayer.start(); /* #if !defined(WIN32) || defined(__CYGWIN__) kbinit(); #endif */ int ch; do { #if defined(WIN32) && !defined(__CYGWIN__) ch = getch(); #else ch = getchar(); #endif ch = toupper( ch ); //if (ch == 'P') //PrintMediaServers(&mplayer); } while( ch != 'Q'); /*#if !defined(WIN32) || defined(__CYGWIN__) kbexit(); #endif */ mplayer.stop(); return 0; }
在Mstar的mips处理器上运行后,设备发现速度比JAVA版本cyberlink要快,通过Intel的测试工具(Intel AV Media Controller)能快速发现到设备