代码改变世界

android 电视盒下XBMC源码功能的简单分析

2012-10-08 15:43 by Terry_龙, ... 阅读, ... 评论, 收藏, 编辑
XBMC 是一个优秀的自由和开源的(GPL)媒体中心软件。XBMC最初为Xbox而开发,现在可以运行在Linux、OSX、Windows系统。 2003年,一些兴趣相投的程序员创建了这个项目。XBMC是一个非盈利的项目,由遍布世界各地的自愿者开发维护。超过50名软件开发人员为XBMC作出贡献,还有超过100名翻译人员努力扩大它的应用范围,使它支持超过30种语言。

 

     由于XBMC一开始设计就是倾向于遥控输入,自身的框架极其强大,容易扩展,用在电视盒上面刚好可以补充小公司在内容不足时的替代品。值得庆幸的是,XBMC的android 源码也开源了,android 电视盒的开发者可以学习或者拿过来改造了。前一篇写xbmc默认中文显示的文章:点击打开 。

    XBMC官方网站:点击打开 。 

 也可直接下载:

  $ git clone git://github.com/xbmc/xbmc.git

 XBMC的WIKI: 点击打开 。 


 

  最近一直在负责xbmc 的扩展,大致对xbmc的结构比较清晰,今天不讲结构目录,网上大把。主讲一些控件的使用的数据填充等。 大致会讲到从一个界面的形成到界面上的元素的交互这方面,基本可以满足一般开发者对现有XBMC简单的界面扩展需要。

 先上一张效果图

 

1):界面的继承

   XBMC使用的是C++编写的界面,所有眼睛能看到的界面都是继承于CGUIWindow(Dialog 继承于CGUIDialog),XBMC又分为不同的类别,比如音乐、视频、图片、天气等,每个类别分别有一个Base界面继承自CGUIWindow用来作为该类别的基类,比如视频的基类为:CGUIWindowVideoBase,假如你要为视频新增一个界面,那么可以继承CGUIWindowVideoBase,实现这个类的一些虚承数即可,非常方便。

  以我为视频增加一个缩略图展示界面的页面为例,代码为:

CGUIWindowVideoThumbList::CGUIWindowVideoThumbList(void)

        :CGUIWindowVideoBase(WINDOW_VIDEO_THUMBLIST,"MyVideoThumb.xml"

  A. WINDOW_VIDEO_THUMBLIST定义在源码里的:xbmc/guilib/Key.h ,代码为:

#define WINDOW_VIDEO_THUMBLIST              10026

  这个常量用来代表这个界面,要使用这个界面可以直接使用,比如打开或者显示该界面可以:

 g_windowManager.ActivateWindow(WINDOW_VIDEO_THUMBLIST);

 另外,想要让XBMC认出这个界面还需要在xbmc/Application.cpp 初始化时添加进来,代码块位于:

bool CApplication::Initialize(){
   ……
g_windowManager.Add(new CGUIWindowVideoThumbList);
……
}

 

 

 B.MyVideoThumb.xml这个文件代表界面元素,可以理解成android 的xml界面,但编写方式和控件的排列方面都不相同,关于界面控件的排布斋在第2点详细说明。到此为止,一个新的界面就算是完成了,下面说说如何在xml上画界面。

 注意:需要在Makefile文件将你新增的文件写进去,以便编译时能够顺利编进去。

2):界面元素

XBMC所支持的控件列表:点击打开 。 

 默认界面存放于android/addons/skin.confluence/720p目录,这里面包含了所有界面的XML,对应的素材包括:声音、字体、语言文字、图片、颜色等也一并在android/addons/skin.confluence此目录,最后生成build.bat文件。

注意:一些经常用的或者通用的布局,可以写在Includes.xml文件里面,以后有需要用到的可以直接写在你需要的xml上,比如:

<include>CommonBackground</include>

以一个panel的控件的XML为例,代码如下:

 <control type="group">

        <include>VisibleFadeEffect</include>
            <control type="panel" id="8000">类型panel,id为8000
                <posx>180</posx> 位于界面x 轴为180
                <posy>20</posy>  位于界面y轴为20
                <width>1160</width> panel 的宽度的1160
                <height>590</height> panel 的高度为590
                <onleft>9000</onleft> 遥控按向左键时如果焦点还在panel里面,并且己经是最左边一个元素时,将焦点切换到ID为9000的控件上
                <onright>60</onright>遥控按向右键时如果焦点还在panel里面,并且己经是最右边一个元素时,将焦点切换到ID为60的控件上
                 <onup>1000</onup>遥控按向上键时如果焦点还在panel里面,并且己经是最顶一个元素时,将焦点切换到ID为1000的控件上
                 <ondown>1000</ondown>遥控按向下键时如果焦点还在panel里面,并且己经是最底一个元素时,将焦点切换到ID为1000的控件上
                 <viewtype label="21371">list</viewtype> 显示类型为列表
                <pagecontrol>60</pagecontrol> 与下面scrollbar绑定,作为该panel的滚动控件 
                 <scrolltime tween="sine" easing="out">200</scrolltime>拖动延时
                <preloaditems>2</preloaditems>预加载项目2
                 元素默认时的控件高度200宽度220,该荐包括一个默认无获得焦点的image(图片)和未获得含焦点的label(文字)

        <itemlayout height="200" width="220"> 
                    <control type="image"> 类型image
                        <posx>1</posx> 位于panel里面的位置是x 轴1
                        <posy>0</posy>位于panel 里面的位置 是y轴0
                        <width>180</width>image宽度180
                        <height>160</height> image高度160
                        <aspectratio>scale</aspectratio>不论图片大小填充整个图片的宽高.keep 为保持图片的大小不拉伸。更多请 点击 。
                        <bordertexture border="5">folder-nofocus.png</bordertexture>image边框纹理图片
                        <bordersize>5</bordersize>边框大小
                        <texture background="true">$INFO[Listitem.Icon]</texture>image图片,ListItem.Icon为获取CFileItemPtr里面的数据,后文会介绍
                    </control>
                    <control type="label">类型label
                        <posx>88</posx>位于panel里面的位置是x 轴88
                         <posy>160</posy>位于panel 里面的位置 是y轴160
                         <width>180</width>label宽度为180
                        <height>25</height>label高度为25
                        <font>font50caps_title</font> 文体类型,该字体定义于:xml同级目录的Font.xml里面,也可以自行设置filename与size
                        <textcolor>white</textcolor>文体颜色
                        <selectedcolor>selected</selectedcolor>选中时颜色 
                        <align>center</align>位于itemLayout的中间x方向
                        <aligny>center</aligny>位于itemLayout的中间y方向
                        <info>ListItem.Label</info>显示信息同样获取自CFileitemPtr,也可自行指定
                    </control>
                    
                </itemlayout>
                元素获得焦点时的控件高度200宽度250,该荐包括一个默认无获得焦点的image(图片)和未获得含焦点的label(文字)

        <focusedlayout  height="200" width="250">
                    
                    <control type="image">
                        <posx>1</posx>
                        <posy>0</posy>
                        <width>180</width>
                        <height>160</height>
                        <aspectratio>scale</aspectratio>
                        <bordertexture border="5">folder-focus.png</bordertexture> 获取焦点时的图片
                        <bordersize>5</bordersize>
                        <texture background="true">$INFO[Listitem.Icon]</texture>
                    </control>
                    <control type="label">
                        <posx>88</posx>
                        <posy>160</posy>
                        <width>180</width>
                        <height>25</height>
                        <font>font50caps_title</font>
                        <textcolor>white</textcolor>
                        <selectedcolor>selected</selectedcolor>
                        <align>center</align>
                        <aligny>center</aligny>
                        <info>ListItem.Label</info>
                    </control>
                </focusedlayout>
            </control>
            <control type="scrollbar" id="60">滚动条
                <posx>1250</posx>
                <posy>20</posy>
                <width>25</width>
                <height>590</height>
                <onleft>8000</onleft>
                <onright>9000</onright>
                <texturesliderbackground border="0,14,0,14">ScrollBarV.png</texturesliderbackground>
                <texturesliderbar border="2,16,2,16">ScrollBarV_bar.png</texturesliderbar>
                <texturesliderbarfocus border="2,16,2,16">ScrollBarV_bar_focus.png</texturesliderbarfocus>
                <textureslidernib>ScrollBarNib.png</textureslidernib>
                <textureslidernibfocus>ScrollBarNib.png</textureslidernibfocus>
                <onleft>500</onleft>    
                <onright>2</onright>
                <showonepage>false</showonepage>
                <orientation>vertical</orientation>方向
            </control>
        </control>

 

3):界面需要实现的几个虚函数

头文件代码为:

#include "GUIWindowVideoBase.h"
#include "ThumbLoader.h"
#include "GUIWindowVideoNav.h"
class CGUIWindowVideoThumbList : public CGUIWindowVideoBase
{
  public:
     
    CGUIWindowVideoThumbList(void);
    virtual ~CGUIWindowVideoThumbList(void);

    virtual bool OnAction(const CAction &action);动作回调函数,不怎么用到
    virtual bool OnMessage(CGUIMessage& message);消息回调函数,处理界面元素的点击消息,有点像android 的handler消息机制 

    virtual bool Update(const CStdString &strDirectory);当界面完成一个更新或者显示一开始显示时调用

     void LoadItemByDirectory(const CStdString &strDirectory);

     void LoadItemByDirectory(const CFileItemList &items);


 protected:
   virtual void OnInitWindow();初始化
   virtual void OnWindowLoaded();加载完毕后
   
   int GetWindowSeletectedItem(int iControl);
   
   CFileItemList* m_vecItems;
   CFileItemList* itemList;
   bool load_done;

  
   CFileItemList* page_index_list;

   CStdString previous_path;
   
   CStdString next_path;

   int pageIndex;


        }; 

 以上几个有添加注释为必须实现函数,XBMC界面控制也基本在这几个回调函数里面进行。

 

4): 数据的加载或者填充

普通的控件如Button、Label之类的加载文字,可以直接使用预定义好的全局方法SET_CONTROL_LABEL(controlID,label)来做。

 而列表加载需要做一个类型List的数据给CGUIMessage,代码为:

 

bool CGUIWindowVideoThumbList::Update(const CStdString &strDirectory)
{     
   
  //if(!load_done){

      CFileItemList list; 
    GetDirectory("plugin://plugin.video.XuZhiTV",list);通过获取目录得到python插件的数据目录

    itemList->Clear();
    for(int i=0;i<list.Size();i++){循环填充进itemList
          
      CFileItemPtr pItem = list.Get(i); 
        
      if(strcmp(pItem->GetLabel().c_str(),"..")==0)
        continue;
        CFileItemPtr cateItem(new CFileItem(pItem->GetLabel()));
        cateItem->SetPath(pItem->GetPath());
        itemList->Add(cateItem);
      }

   通过消息将列表广播出去,加载列表 

      CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LOAD_CATEGORY_LIST_ID, 00, itemList);
      g_windowManager.SendMessage(msg);

//--------------------end------------------------

//-------------item list---------------------------
     CFileItemList firstList;
     GetDirectory(itemList->Get(0)->GetPath(),firstList);得到插件目录的子目录
//-------------------end-----------------------


    /*  load_done=true;
  
*/

    LoadItemByDirectory(firstList); 加载子项

  //}
  return true;
}

 

LoadItemByDirectory方法代码:

void CGUIWindowVideoThumbList::LoadItemByDirectory(const CFileItemList &items){
    m_vecItems->Clear();
    page_index_list->Clear();
     for (int i=0;i<items.Size(); ++i)
      {
          CFileItemPtr pItem = items.Get(i); 
        if(strcmp(pItem->GetLabel().c_str(),"..")==0)
            continue;
        CFileItemPtr item(new CFileItem(pItem->GetLabel()));
        item->SetThumbnailImage(pItem->GetThumbnailImage());获取网络上的图片给上面panel 的image
         item->SetPath(pItem->GetPath());
        
        if(pItem->GetLabel().Find("|")>0){
            item->SetIntParam(-1);
            CFileItemPtr ptr(new CFileItem(pItem->GetLabel())); 获取label给上面panel 的label
            ptr->SetPath(pItem->GetPath());
            page_index_list->Add(ptr);
            continue;
        }else{
            item->SetIntParam(0);
        }
        item->SetIconImage("DefaultVideoCover.png");
        
        item->SetLabelPreformated(true);
        
        m_vecItems->Add(item);
      }广播消息加载内容
     CGUIMessage refresh(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LOAD_ITEM_LIST_ID, 00, m_vecItems);
     bool isRefresh= g_windowManager.SendMessage(refresh);
     if(isRefresh){
         
         int m_size=page_index_list[0].Size();
        CFileItemPtr ptr=page_index_list[0].Get(0);
        if(m_size==0){
            SET_CONTROL_HIDDEN(CONTROL_NEXT_ID);
            SET_CONTROL_HIDDEN(CONTROL_PREVIOUSE_ID);
            SET_CONTROL_LABEL(CONTROL_PAGE_COUNT_ID,"");
        }else{
            SET_CONTROL_LABEL(CONTROL_PAGE_COUNT_ID,ptr->GetLabel().Right(6));
            SET_CONTROL_VISIBLE(CONTROL_NEXT_ID);
            SET_CONTROL_VISIBLE(CONTROL_PREVIOUSE_ID);
        }
        
        switch(m_size){
            case 0:
                previous_path="";
                next_path="";
                break;
            case 1:{
                    CStdString control_text=ptr->GetLabel().Left(ptr->GetLabel().Find("|"));
                    if(strcmp(control_text,"down")==0){
                        next_path=ptr->GetPath();
                    }else{
                        previous_path=ptr->GetPath();
                    }
                }
                break;
            case 2:
                previous_path=ptr->GetPath();
                next_path=page_index_list[0].Get(1)->GetPath();
                break;
        }
     }

 

 5):点击事件的处理

 

 点击事件可以重写onclick,也可以由OnMessage函数处理,都可以。处理非常简单代码为:

bool CGUIWindowVideoThumbList::OnMessage(CGUIMessage& message)
{
    if (message.GetMessage() == GUI_MSG_CLICKED)消息类型为点击时,message不止可以处理点击,还有很多事件可以处理。
    {
    int iControl = message.GetSenderId();获得点击控件的ID
    if(iControl == 2000){ID等于2000时
       //处理点击时响 应的代码
    }
  }
    return CGUIWindowVideoBase::OnMessage(message);

 更多关于XBMC功能源码方面欢迎讨论。