簡介:本文使用cocos2d-x和libvlc兩大免費開源的跨平台框架,實現一個視頻播放器。開發工具使用Visual Studio 2010,測試運行平台為Windows(之前只測了windows,現在mac和linux下也測試通過,ios和android還未測試,很多看了這篇博客的朋友都問過ios和android下能不能用,這點我也無法確定,如果有高手一這兩平台下任一平台測試通過麻煩通知一聲)。cocos2d-x版本2.0.3,VLC版本2.0.5。
目前游戲程序開發者大部分在以下幾個平台上開發游戲:Windows、Mac OS X、IOS和Android。開發2D游戲且跨平台,cocos2d-x是個非常不錯的選擇,而libvlc也提供了各大平台的支持,因此使用這兩大框架理論上可以做到一次編寫,全平台運行的目的。
打開Visual Studio 2010,新建一個Cocos2d-win32 Application項目,我這里叫Cocos2dPlayer,配置好整個項目,直到可以編譯通過且能運行(如何配置可以參考網上很多帖子教程,在此就不多說,見諒)。另外還要加上vlc頭文件、庫文件和動態鏈接庫文件,我是直接下載vlc播放器的安裝版本然后在sdk目錄中把vlc文件夾拷貝到Visual Studio 2010的VC\include目錄下,庫文件和動態鏈接庫文件則放在本項目的Debug.win32和Release.win32目錄下。
接下來進入正題:
創建文件MoviePlayer.h和MoviePlayer.cpp
MoviePlayer.h
#ifndef __MOVIEPLAYER_H__ #define __MOVIEPLAYER_H__ /**************************************************************************** http://www.cnblogs.com/evan-cai/ Author: Evan-Cai Date: 2013-01-25 ****************************************************************************/ #include <vlc\vlc.h> #include "sprite_nodes\CCSprite.h" NS_CC_BEGIN class MoviePlayer : public CCSprite { public: ~MoviePlayer(); static MoviePlayer * instance(void); bool init(void); void play(char *path); void stop(void); void pause(void); void draw(void); protected: MoviePlayer(); private: libvlc_instance_t *vlc; libvlc_media_player_t *vlc_player; unsigned int width; unsigned int height; static MoviePlayer * _instance; }; NS_CC_END #endif
MoviePlayer.cpp
#include "MoviePlayer.h" #include "CCDirector.h" NS_CC_BEGIN MoviePlayer * MoviePlayer::_instance = 0; static char * videobuf = 0; static void *lock(void *data, void **p_pixels) { *p_pixels = videobuf; return NULL; } static void unlock(void *data, void *id, void *const *p_pixels) { assert(id == NULL); } static void display(void *data, void *id) { (void) data; assert(id == NULL); } MoviePlayer::MoviePlayer(): vlc(0), vlc_player(0) { init(); } MoviePlayer::~MoviePlayer() { CCSprite::~CCSprite(); free(videobuf); libvlc_media_player_stop(vlc_player); libvlc_media_player_release(vlc_player); libvlc_release(vlc); } bool MoviePlayer::init(void) { vlc = libvlc_new(0, NULL); vlc_player = libvlc_media_player_new(vlc); CCSize size = CCDirector::sharedDirector()->getWinSize(); width = size.width; height = size.height; videobuf = (char *)malloc((width * height) << 2); memset(videobuf, 0, (width * height) << 2); libvlc_video_set_callbacks(vlc_player, lock, unlock, display, NULL); libvlc_video_set_format(vlc_player, "RGBA", width, height, width << 2); CCTexture2D *texture = new CCTexture2D(); texture->initWithData(videobuf, kCCTexture2DPixelFormat_RGBA8888, width, height, size); return initWithTexture(texture); } void MoviePlayer::play(char *path) { libvlc_media_t *media = libvlc_media_new_path(vlc, path); libvlc_media_player_set_media(vlc_player, media); libvlc_media_release(media); libvlc_media_player_play(vlc_player); } void MoviePlayer::stop(void) { libvlc_media_player_stop(vlc_player); } void MoviePlayer::pause(void) { libvlc_media_player_pause(vlc_player); } void MoviePlayer::draw(void) { CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); CCAssert(!m_pobBatchNode, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); CC_NODE_DRAW_SETUP(); ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst ); if (m_pobTexture != NULL) { ccGLBindTexture2D( m_pobTexture->getName() ); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,(uint8_t *) videobuf); } else { ccGLBindTexture2D(0); } // // Attributes // ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); #define kQuadSize sizeof(m_sQuad.bl) long offset = (long)&m_sQuad; // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); } MoviePlayer * MoviePlayer::instance() { if(_instance == 0) _instance = new MoviePlayer(); return _instance; } NS_CC_END
然后編輯HelloWorldScene.cpp文件的init函數,最后函數如下:
(說明:我把HelloWorld類改成了Cocos2dPlayer類,所以瀏覽本文章的朋友只要把下面的Cocos2dPlayer::init改成HelloWorld::init就可以編譯運行了,另外Can't Wait.mp4是我在網絡上下載下來的mp4文件,請朋友你自行更改名稱^_^)
bool Cocos2dPlayer::init() { bool bRet = false; do { ////////////////////////////////////////////////////////////////////////// // super init first ////////////////////////////////////////////////////////////////////////// CC_BREAK_IF(! CCLayer::init()); ////////////////////////////////////////////////////////////////////////// // add your codes below... ////////////////////////////////////////////////////////////////////////// // 1. Add a menu item with "X" image, which is clicked to quit the program. // Create a "close" menu item with close icon, it's an auto release object. CCMenuItemImage *pCloseItem = CCMenuItemImage::create( "CloseNormal.png", "CloseSelected.png", this, menu_selector(Cocos2dPlayer::menuCloseCallback)); CC_BREAK_IF(! pCloseItem); // Place the menu item bottom-right conner. pCloseItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20)); // Create a menu with the "close" menu item, it's an auto release object. CCMenu* pMenu = CCMenu::create(pCloseItem, NULL); pMenu->setPosition(CCPointZero); CC_BREAK_IF(! pMenu); // Add the menu to Cocos2dPlayer layer as a child layer. this->addChild(pMenu, 1); // 2. Add a label shows "Hello World". // Create a label and initialize with string "Hello World". //CCLabelTTF* pLabel = CCLabelTTF::create("Let's PLAY!", "Arial", 24); //CC_BREAK_IF(! pLabel); // Get window size and place the label upper. CCSize size = CCDirector::sharedDirector()->getWinSize(); //pLabel->setPosition(ccp(size.width / 2, size.height - 50)); // Add the label to Cocos2dPlayer layer as a child layer. //this->addChild(pLabel, 1); // 3. Add add a splash screen, show the cocos2d splash image. MoviePlayer* pPlayer = MoviePlayer::instance(); // Place the sprite on the center of the screen pPlayer->setPosition(ccp(size.width/2, size.height/2)); // Add the sprite to Cocos2dPlayer layer as a child layer. this->addChild(pPlayer, 0); pPlayer->play("Can't Wait.mp4"); bRet = true; } while (0); return bRet; }
如果您遇到這種情況:release版本程序調用libvlc接口出現異常