搜索
搜索关键词:
Tags
存档
最新文章
最新回复
链接
|
分页共3页 1 2 3 下一页 最后一页
|
|
关于PDF排版
|
原文地址 http://lycoder.javaeye.com/blog/609989
“PDFBox看起来非常的方便,它的API功能强大。甚至能和Lucene进行无缝的结合。但是它有一个致命的弱点,就是它不支持中文。要提取中文的文本,可以采用另一个非常出色的工具xpdf。”
于是我决定自己比较一下这两种方法处理中文pdf文档时在时间性能、读取效果等各个方面的效果。
一、关于XPDF和PDFBOX 1.xpdf xpdf只是一个软件,通过java采用命令行调用,并获取输出结果,如此来说使用简单,但是相当受限,如:无法跨平台,无法处理特定格式(表格等),无法处理图片和其他附件。这种调用必定限制了它的灵活性。
2.pdfbox pdfbox(一个BSD许可下的源码开放项目)是一个为开发人员读取和创建PDF文档而准备的纯Java类库。 二、XPDF的配置 1.工具包下载 点这里 下载 我下载的是: xpdf-3.02pl4-win32.zip 另外还需要一个语言包: xpdf-chinese-simplified.tar.gz
2.工作路径设置 参考资料点这里 在本文中以 c:\xpdftest\xpdf 作为xpdf的工作路径。 将 xpdf-3.02p14-win32.zip 解压到 c:\xpdftest\xpdf 下。 将 xpdf-chinese-simplified.tar.gz 解压到 c:\xpdftest\xpdf\xpdf-chinese-simplified 下。
解压后的目录结构如图1所示:
3.修改配置文件 为了启用中文简体语言包,必须将 xpdf-chinese-simplified 目录下的 sample-xpdfrc 文件进行如下配置,并将其另存为 xpdfrc 文件 。 注意:此文件为配置文件,而且名称必须是 xpdfrc 。如果是别的名字,即使调用 pdftotext.exe 时,传入 ” -cfg xpdfrc2 ” 来告诉 xpdf 配置文件的名字,好像 pdftotext.exe 也并没有使用这个配置文件。所以为了减少误解,请您将配置文件直接命名为 xpdfrc 。
修改 sample-xpdfrc 文件之一 在文件后面 加上一段话 :
Txt代码 #----- begin Chinese Simplified support package (2004-jul-27)
cidToUnicode Adobe-GB1 C:/xpdftest/xpdf/xpdf-chinese-simplified/Adobe-GB1.cidToUnicode
unicodeMap ISO-2022-CN C:/xpdftest/xpdf/xpdf-chinese-simplified/ISO-2022-CN.unicodeMap
unicodeMap EUC-CN C:/xpdftest/xpdf/xpdf-chinese-simplified/EUC-CN.unicodeMap
unicodeMap GBK C:/xpdftest/xpdf/xpdf-chinese-simplified/GBK.unicodeMap
cMapDir Adobe-GB1 C:/xpdftest/xpdf/xpdf-chinese-simplified/CMap
toUnicodeDir C:/xpdf/chinese-simplified/CMap
#displayCIDFontTT Adobe-GB1 /usr/..../gkai00mp.ttf
#----- end Chinese Simplified support package
#----- begin Chinese Simplified support package (2004-jul-27)
cidToUnicode Adobe-GB1 C:/xpdftest/xpdf/xpdf-chinese-simplified/Adobe-GB1.cidToUnicode
unicodeMap ISO-2022-CN C:/xpdftest/xpdf/xpdf-chinese-simplified/ISO-2022-CN.unicodeMap
unicodeMap EUC-CN C:/xpdftest/xpdf/xpdf-chinese-simplified/EUC-CN.unicodeMap
unicodeMap GBK C:/xpdftest/xpdf/xpdf-chinese-simplified/GBK.unicodeMap
cMapDir Adobe-GB1 C:/xpdftest/xpdf/xpdf-chinese-simplified/CMap
toUnicodeDir C:/xpdf/chinese-simplified/CMap
#displayCIDFontTT Adobe-GB1 /usr/..../gkai00mp.ttf
#----- end Chinese Simplified support package 注意:路径要跟自己配置的一样。
修改 sample-xpdfrc 文件之二 另外,配置文件中原先没有加上一个“ textPageBreaks ”控制。为了避免这个分页符号,我们需要在 sample-xpdfrc 文件 “ text output control ”下面 加上一段话 : Txt代码 # If set to "yes", text extraction will insert page # breaks (form feed characters) between pages. This # defaults to "yes". textPageBreaks no
# If set to "yes", text extraction will insert page # breaks (form feed characters) between pages. This # defaults to "yes". textPageBreaks no 设置 textPageBreaks 为 no 的意思是:在 PDF 文档的两页之间不加入分页符号。 之所以这样,是因为这个符号有时候会引起 SAX 解析 XML 上的困难。
修改 sample-xpdfrc 文件之三 配置文件中原先把 textEncoding 注释了。这样默认的字符集是 Latin1 。我们必须打开它,并且就是指定 textEncoding 为 UTF-8 ,而不是 GB2312 。即修改这句话 : Txt代码 textEncoding UTF-8
textEncoding UTF-8 三、PDFBOX的配置
请点这里 查看PDFBOX的配置。
四、工程调用示范 在自己的常用工作环境下新建一个工程PdfTest,并在此工程下新建一个包pdfToText。 此包包括三个类: TestPdfToText.java 包括Main函数,调用并测试xpdf和pdfbox对PDF文档的处理效果。 PdfboxToText.java 用pdfbox来处理PDF文档。 XpdfToText.java 用xpdf来处理PDF文档。 目录结构如图2所示:
在C盘根目录下有061231.pdf,在工程中相应设置路径进行测试,以下是源代码 : TestPdfToText.java Java代码 package pdfToText; /** * 功能描述:测试用XPDF和PDFBOX来读取中文PDF文件生成TXT文件的效果 * @author Emily * @Create 2010-03-07 */ public class TestPdfToText {
/** * @param args */ public static void main(String[] args) { String rootPath = "c:\\061231"; //pdf文件路径 String pdffile = rootPath + ".pdf"; //用xpdf生成的txt文件路径 String xpdfToTxtfile = rootPath + "_xpdf.txt"; //用pdfbox生成的txt文件路径 String pdfboxToTxtfile = rootPath + "_pdfbox.txt"; //XPDF try{ long begin = System.currentTimeMillis(); XpdfToText xpToTxt = new XpdfToText(pdffile); xpToTxt.toTextFile(xpdfToTxtfile); long end = System.currentTimeMillis(); System.out.println("xpdf\t cost:\t" + (end - begin) + " ms"); }catch(Exception e){ e.printStackTrace(); } //PDFBOX try{ long begin = System.currentTimeMillis(); PdfboxToText pbToTxt = new PdfboxToText(pdffile); pbToTxt.toTextFile(pdfboxToTxtfile); long end = System.currentTimeMillis(); System.out.println("pdfbox\t cost:\t" + (end - begin) + " ms"); }catch(Exception e){ e.printStackTrace(); }
} }
package pdfToText; /** * 功能描述:测试用XPDF和PDFBOX来读取中文PDF文件生成TXT文件的效果 * @author Emily * @Create 2010-03-07 */ public class TestPdfToText {
/** * @param args */ public static void main(String[] args) { String rootPath = "c:\\061231"; //pdf文件路径 String pdffile = rootPath + ".pdf"; //用xpdf生成的txt文件路径 String xpdfToTxtfile = rootPath + "_xpdf.txt"; //用pdfbox生成的txt文件路径 String pdfboxToTxtfile = rootPath + "_pdfbox.txt"; //XPDF try{ long begin = System.currentTimeMillis(); XpdfToText xpToTxt = new XpdfToText(pdffile); xpToTxt.toTextFile(xpdfToTxtfile); long end = System.currentTimeMillis(); System.out.println("xpdf\t cost:\t" + (end - begin) + " ms"); }catch(Exception e){ e.printStackTrace(); } //PDFBOX try{ long begin = System.currentTimeMillis(); PdfboxToText pbToTxt = new PdfboxToText(pdffile); pbToTxt.toTextFile(pdfboxToTxtfile); long end = System.currentTimeMillis(); System.out.println("pdfbox\t cost:\t" + (end - begin) + " ms"); }catch(Exception e){ e.printStackTrace(); }
} } PdfboxToText.java Java代码 package pdfToText;
import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import org.pdfbox.pdfparser.PDFParser; import org.pdfbox.pdmodel.PDDocument; import org.pdfbox.util.PDFTextStripper;
public class PdfboxToText { private String filePath; public PdfboxToText(String filePath){ this.filePath = filePath; } public String getTextFromPdf(){ String result = null; FileInputStream is = null; PDDocument document = null; try { is = new FileInputStream(filePath); PDFParser parser = new PDFParser(is); parser.parse(); document = parser.getPDDocument(); PDFTextStripper stripper = new PDFTextStripper(); result = stripper.getText(document); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (is != null) { try {is.close();}catch(IOException e){e.printStackTrace();} } if (document != null) { try{document.close();}catch (IOException e){e.printStackTrace();} } } return result; }
public void toTextFile(String filePath){ String pdfContent = getTextFromPdf(); try{ File f = new File(filePath); if(!f.exists()){ System.out.println("not exist"); f.createNewFile(); } BufferedWriter output = new BufferedWriter(new FileWriter(f)); output.write(pdfContent); output.close(); }catch (Exception e) { e.printStackTrace(); } } }
package pdfToText;
import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import org.pdfbox.pdfparser.PDFParser; import org.pdfbox.pdmodel.PDDocument; import org.pdfbox.util.PDFTextStripper;
public class PdfboxToText { private String filePath; public PdfboxToText(String filePath){ this.filePath = filePath; } public String getTextFromPdf(){ String result = null; FileInputStream is = null; PDDocument document = null; try { is = new FileInputStream(filePath); PDFParser parser = new PDFParser(is); parser.parse(); document = parser.getPDDocument(); PDFTextStripper stripper = new PDFTextStripper(); result = stripper.getText(document); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (is != null) { try {is.close();}catch(IOException e){e.printStackTrace();} } if (document != null) { try{document.close();}catch (IOException e){e.printStackTrace();} } } return result; }
public void toTextFile(String filePath){ String pdfContent = getTextFromPdf(); try{ File f = new File(filePath); if(!f.exists()){ System.out.println("not exist"); f.createNewFile(); } BufferedWriter output = new BufferedWriter(new FileWriter(f)); output.write(pdfContent); output.close(); }catch (Exception e) { e.printStackTrace(); } } } XpdfToText.java Java代码 package pdfToText;
import java.io.File; import java.io.IOException;
public class XpdfToText { // PDF文件名 private File pdffile; // 转换器的存放位置,默认在c:\xpdftest\xpdf下面 private String CONVERTOR_STORED_PATH = "c:\\xpdftest\\xpdf\\"; // 转换器的名称,默认为pdftotext private String CONVERTOR_NAME = "pdftotext";
// 构造函数,参数为pdf文件的路径 public XpdfToText(String pdffile) throws IOException { this.pdffile = new File(pdffile); }
// 将pdf转为文本文档,参数为目标文件的路径 public void toTextFile(String targetfile) throws IOException { toTextFile(targetfile, true); }
// 将pdf转为文本文档,参数1为目标文件的路径, // 参数2为true则表示使用PDF文件中的布局 public void toTextFile(String targetfile, boolean isLayout) throws IOException { String[] cmd = getCmd(new File(targetfile), isLayout); Runtime.getRuntime().exec(cmd); }
// 获取PDF转换器的路径 public String getCONVERTOR_STORED_PATH() { return CONVERTOR_STORED_PATH; }
// 设置PDF转换器的路径 public void setCONVERTOR_STORED_PATH(String path) { if (!path.trim().endsWith("\\")) path = path.trim() + "\\"; this.CONVERTOR_STORED_PATH = path; }
// 解析命令行参数 private String[] getCmd(File targetfile, boolean isLayout) {
// 命令字符 String command = CONVERTOR_STORED_PATH + CONVERTOR_NAME; // PDF文件的绝对路径 String source_absolutePath = pdffile.getAbsolutePath(); // 输出文本文件的绝对路径 String target_absolutePath = targetfile.getAbsolutePath(); // 保持原来的layout String layout = "-layout"; // 设置编码方式 String encoding = "-enc"; String character = "GBK"; // 设置不打印任何消息和错误 String mistake = "-q"; // 页面之间不加入分页 String nopagebrk = "-nopgbrk"; // 如果isLayout为false,则设置不保持原来的layout if (!isLayout) layout = ""; return new String[] { command, layout, encoding, character, mistake,
nopagebrk, source_absolutePath, target_absolutePath }; } }
package pdfToText;
import java.io.File; import java.io.IOException;
public class XpdfToText { // PDF文件名 private File pdffile; // 转换器的存放位置,默认在c:\xpdftest\xpdf下面 private String CONVERTOR_STORED_PATH = "c:\\xpdftest\\xpdf\\"; // 转换器的名称,默认为pdftotext private String CONVERTOR_NAME = "pdftotext";
// 构造函数,参数为pdf文件的路径 public XpdfToText(String pdffile) throws IOException { this.pdffile = new File(pdffile); }
// 将pdf转为文本文档,参数为目标文件的路径 public void toTextFile(String targetfile) throws IOException { toTextFile(targetfile, true); }
// 将pdf转为文本文档,参数1为目标文件的路径, // 参数2为true则表示使用PDF文件中的布局 public void toTextFile(String targetfile, boolean isLayout) throws IOException { String[] cmd = getCmd(new File(targetfile), isLayout); Runtime.getRuntime().exec(cmd); }
// 获取PDF转换器的路径 public String getCONVERTOR_STORED_PATH() { return CONVERTOR_STORED_PATH; }
// 设置PDF转换器的路径 public void setCONVERTOR_STORED_PATH(String path) { if (!path.trim().endsWith("\\")) path = path.trim() + "\\"; this.CONVERTOR_STORED_PATH = path; }
// 解析命令行参数 private String[] getCmd(File targetfile, boolean isLayout) {
// 命令字符 String command = CONVERTOR_STORED_PATH + CONVERTOR_NAME; // PDF文件的绝对路径 String source_absolutePath = pdffile.getAbsolutePath(); // 输出文本文件的绝对路径 String target_absolutePath = targetfile.getAbsolutePath(); // 保持原来的layout String layout = "-layout"; // 设置编码方式 String encoding = "-enc"; String character = "GBK"; // 设置不打印任何消息和错误 String mistake = "-q"; // 页面之间不加入分页 String nopagebrk = "-nopgbrk"; // 如果isLayout为false,则设置不保持原来的layout if (!isLayout) layout = ""; return new String[] { command, layout, encoding, character, mistake, nopagebrk, source_absolutePath, target_absolutePath }; } }
五、测试结果和总结 1.txt文件大小 一个大小为74KB的PDF文档经处理为txt文档后,大小明显减小。 经xpdf处理后生成了10KB的txt文件。 经pdfbox处理后生成了12KB的txt文件。
2.时间性能 从运行结果来看,xpdf处理的速度明显大大快于pdfbox的处理速度,几乎是1/10。 如图3所示。
3.读取效果 在设置了保持原PDF文档的布局的情况下,xpdf读取的效果如图4所示
若不保持原PDF文的的布局,xpdf读取的效果如图5所示
经pdfbox读取的效果如图6和图7所示。
4.分析总结 从以上调用结果可以发现,在时间性能和空间性能上,xpdf都明显优于pdfbox 。在最关键的读取效果上,pdfbox会自动在某些读取文字中加入一些格式,比如回车、空格等,造成了更不好的效果。至于在某些PDF文档的格式会读出乱码的情况上,两种方法读出的乱码都是比较一致的,这应该是由于这两个方法的缺陷造成的。
综上所示,如果不要求很高的移植性的话,采用xpdf应该是比较好的方法 。
|
|
|
|
|
Windows版MPlayer
|
原文地址 http://forums.mozine.cn/index.php?showtopic=124&mode=threaded
1、本文遵循GPL/LGPL协议,欢迎自由转载,但请注明作者出处。
2、本文首发赢政。由于在那里被问到了几个MPlayer的问题,上网查了一下,发现关于Windows版MPlayer的文章较少,即使是官方中文文档(http://www.mplayerhq.hu/DOCS/HTML/zh/documentation.html),也侧重于Linux平台的安装使用。于是结合自己的使用经验写了一篇Windows平台下使用源代码编译MPlayer的帖子,在文章末尾简略的提了一下MPlayer命令行及GUI的使用。见笑了。
3、Mplayer一段时间以来一直称得上Linux平台媒体播放软件的王者,其Windows移植版同样出色。但是最近Mplayer的日子过得挺尴尬。先是在Linux(KDE)平台上被媒体播放器的新贵Kaffeine 一通穷追猛打,然后又和自己的子项目FFmpeg一起惹上了莫名其妙的版权官司。(http://www.mplayerhq.hu/homepage/index.html)虽然目前Mplayer 开发工作仍在正常进行,但前途依然是个未知数。作为一个Mplayer 的忠实拥护者,我只能默默地祈祷它一路走好!
4、本文主要参考文档:http://www4.mplayerhq.hu/MPlayer/releases/...MinGW-Howto.txt 5、我的机器是NorthWood的赛扬2.0,winxp sp2 ,从编译过程来讲,A贩们的U和其他windows操作系统应该大同小异。
6、时间仓促,错漏难免,敬请批评指正,谢谢!
一、一般在Windows平台使用MPlayer的人大都会选择 KK编译版,相当出色和好用的版本,那么为什么还要费时费力地从源代码编译安装MPlayer?嘿嘿,我想有几个理由吧:
1、命令行下执行MPlayer.exe你会发现,Mplayer的windows发行版默认都只是针对MMX和MMX2指令集进行的编译(如图),而它的源代码还支持SSE,SSE2,3DNOW!和3dnow-dsp!指令集,如果你有一颗比较新的CPU,通过编译源代码加入对以上几个指令集的支持,以达到更好的效果和更低的资源占用,是一件比较爽的事情。
2、自己编译的MPlayer可以自定义一些性能选项。比如说,默认的MPlayer并不支持2GB以上的单个文件,这就是为什么有人使用MPlayer播放HDTV影片其效果相当糟糕的原因。 你可以通过自己编译加上对它的支持。
3、MPlayer每天都会根据前一天的工作发布一个CVS的完整源代码包,只要你喜欢,每天你都可以编译一个最新的版本——你可以品尝到MPlayer最新的性能——当然,也可能包括最新的bug
4、通过编译安装,除了打造完全适合自己机器的软件外,还能多学一点电脑知识。
5、好玩。
如果以上五个理由没有打动你,那你就不要编译安装了,老老实实的下载上面提到的KK版,也是相当好用的。
二、安装前的准备工作
1、别看我们说是在windows下编译安装MPlayer,但是win自身并不提供相关工具。我们还需要安装两个软件,去 http://www.mingw.org/download.shtml 下载MinGW-3.2.0-rc-3.exe和MSYS-1.0.10.exe ,首先双击安装MinGW-3.2.0-rc-3.exe,这个和普通的win程序安装没什么区别,一路next就可以搞定;然后双击安装MSYS- 1.0.10.exe,这个在安装结束的时候会弹出对话框:"Do you wish to continue with the post install? [yn ]"选y后,又会弹出一个"Do you have MinGW installed? [yn ]" 也是选y,然后让你给出MinGW的安装路径,如果是默认的话应当填C:/mingw(注意用“/”而不是“\”)安装结束后会在桌面生成一个MSYS的图标,双击即可执行。
MinGW 和MSYS究竟是干什么用的?呵呵,我一直都把它们理解为Linux部分工具软件和库+shell命令行的Windows移植版。为了写这篇文章专门搜了一下,原来MinGW是指只用自由软件来生成纯粹的Win32可执行文件的编译环境,它是Minimalist GNU on Windows的略称。——反正就你能看见的部分来说,它就是一个类Unix/Linux的命令行式的软件编译环境。
2、下载dx7的头文件(http://www.mplayerhq.hu/MPlayer/releases/w.../dx7headers.tgz) 解压后把里面的全部文件复制到(c:\mingw\include)
三、开始下载安装一些MPlayer编译所依赖的软件和lib等东东
1、freetype(OSD字幕用)
软件主页:http://www.gnu.org/software/libiconv/
需要文件:libiconv-1.9.1.tar.gz
这个文件和下面提到的文件在windows下都可以使用WinRAR解压。解压后把libiconv-1.9.1目录放在,比如说C盘下面,然后双击打开MSYS,输入
cd C:\ libiconv-1.9.1
注:打开libiconv-1.9.1目录,也可以按需要指定其他目录(下同)。回车,然后输入:
./configure --prefix=/mingw --disable-shared
注:配置代码命令,其中--prefix=c:/mingw为指定目录命令, --disable-shared为取消共享。回车,等待执行完毕后,输入:
make
注:编译命令。回车,等待执行完毕后,输入:
make install
注:编译安装命令。
等待执行完毕后,如果一切顺利,没有报错。那么到此就算完成了一个软件的安装。与下面的各个步骤大同小异,下面我就写的简单一些了。
2、freetype2 软件主页:http://sourceforge.net/project/showfiles.php?group_id=3157 需要文件:freetype-2.1.9.tar.bz2 同上一样,解压,然后 cd freetype-2.1.9 make 注:这个软件不需要./configure make install 原文有错,应该要./configure
3、zlib 软件主页:http://www.gzip.org/zlib/ 需要文件:zlib-1.2.2.tar.bz2 解压 cd zlib-1.2.1 make make install
4、libpng 软件主页:http://sourceforge.net/project/showfiles.php?group_id=5624 所需文件:libpng-1.2.8-config.tar.gz 解压 cd libpng-1.2.8-config ./configure --prefix=c:/mingw --disable-shared make make install
5、libjpeg 软件主页:http://www.ijg.org/ 所需文件:jpegsrc.v6b.tar.gz 解压 cd jpeg-6b ./configure --prefix=/mingw/ --enable-static make cp .libs/libjpeg.a c:/mingw/lib/ cp jpeglib.h jconfig.h jmorecfg.h c:/mingw/include/
6、libregif 软件主页:http://armory.nicewarrior.org/projects/libregif/ 所需文件:libregif 4.1.6 解压 cd libregif-4.1.5 ./configure --prefix=/mingw make make install
7、nasm 软件主页:http://sourceforge.net/project/showfiles.php?group_id=6208 所需文件:nasm-0.98.39.tar.bz2 解压 cd nasm-0.98.38 ./configure --prefix=/mingw make mkdir c:/mingw/man/man1 make install
8、lame 软件主页:http://lame.sourceforge.net/download/download.html 所需文件:lame3.96.1.tar.gz 解压 cd lame-3.96.1 ./configure --prefix=/mingw --disable-shared --disable-decoder make make install
9、xvid 软件主页:http://www.xvid.org/downloads.html 所需文件:xvidcore-1.0.3.tar.bz2 (http://downloads.xvid.org/downloads/) 这个软件最新的1.1beta版从我的机子上跑的情况来看,似乎对原来版本的兼容性有点问题,大家还是用旧的1.0.3版本的吧。 解压 cd xvidcore-1.0.3/build/generic ./configure --prefix=c:/mingw --disable-shared make make install mv c:/mingw/lib/xvidcore.a c:/mingw/lib/libxvidcore.a
10、x264 软件主页:http://subversion.tigris.org/servlets/Proj...ist?folderID=91 所需文件:svn-win32-1.1.4.zip 解压后将 \bin 文件夹内的所有文件复制到C:\mingw\bin文件夹内。 原文错误,svn只是代码管理工具.x264下载地址: http://forum.doom9.org/showthread.php?t=89979 下载后解压,然后 ./configure --prefix=/mingw make make install
11、live 下载地址:http://www.live555.com/liveMedia/public/ 所需文件:live555-latest.tar.gz 解压 cd live genMakefiles mingw make
12、RealCodecs
下载附件中的文件(已分卷),将其解压到某个路径备用。
至此,依赖软件和库文件的配置安装结束。
四、编译安装MPlayer
1、下载源代码包
首先去http://www.mplayerhq.hu/homepage/design7/dload.html 下载MPlayer的源代码包,依据你的个人喜好,你可以下载正式发行的源码版本,比如MPlayer v1.0pre6a source,也可以下载每天更新的CVS版本。
然后去http://www4.mplayerhq.hu/homepage/design7/codecs.html 下载那个名叫Windows all的解码器包。
2、两个包全部解压
3、用cd命令进入MPlayer源码的目录
4、./configure --help
注:执行这一步可以得到该软件支持的./configure的附加条件,可以根据自己的机器情况选用。
其中有些条件是默认支持的,比如说,sse2,3dnow!等指令集的自动检测/支持,real及win32媒体文件的支持,流媒体的支持等等,你可以在附加条件中忽略它们。(有的时候,某些条件未必能够监测得出来。你可以注意一下下一步的 ./configure 后的执行输出,里面包含了所有的条件执行信息,如果有没有认出的,你可以手动指定。)
5、下面就是./configure步骤了,这是我的配置,你可以根据自己的情况更改
./configure --prefix=D:/MPlayer --enable-win32 --enable-real --enable-live --enable-directx --enable-dshow --with-codecsdir=D:/MPlayer/codecs --with-win32libdir=D:/MPlayer/codecs --with-reallibdir=D:/MPlayer/realcodec --with-livelibdir=D:/MPlayer/codecs --enable-static --enable-largefiles --disable-mencoder 其中: --prefix=D:/MPlayerr 为自定义Mplayer的安装路径。 --with-codecsdir=D:/MPlayer/codecs 我把下载的那个/windows-all-20050115 的解码包解压到D:/MPlayer/codecs,这个命令是指定它的路径。(下面的win32也指向这个路径就行) --with-reallibdir=D:/MPlayer/realcodec 记得上面第12步中我们解压备用的那个RealCodecs吗?在这里指定它的路径。 --with-livelibdir=D:/MPlayer/live 上面第11步中我们编译的那个live文件的路径。 --enable-largefiles 支持2GB以上的单个文件——这恐怕对于HDTV爱好者来说是至关重要的。 --enable-directx 和 --enable-dshow 这两项实际上是“自动监测”的,但是有一次在我的机器上没有认出来,还是写一下吧。 --enable-static 是必须的,请注意一下。 --disable-mencoder mencoder这东东我用不到,disable了。 注意:如果你想将编译好的MPlayer.exe能够运行在不同的机器上,可以加上 --enable-runtime-cpudetection 选项;如果只是用在自己的机器和系统上,那就不要加这个。
请注意一下 ./configure 以后的输出结果,在其中可能就能找到下次需要改进的地方。
原文太多罗唆,精简如下: ./configure --prefix=D:/MPlayer --enable-win32 --enable-real --enable-live --enable-directx --enable-dshow --with-codecsdir=codecs --with-livelibdir=live --enable-static --enable-largefiles --disable-mencoder
6、make
如果你是1.0G以下的CPU,你大可以去午睡一会儿了。需要比较长的时间。
7、make install
好了,大功告成。去D:\MPlayer下看看,在bin文件夹下就可以找到Mplayer.exe了。
将bin下的东西拷到/d/Mplayer下.lib下的东西也要拷出来.删除codecs,live之外的文件夹.(usr,man之类).如果对命令行有兴趣,将/d/mplayer加入系统path.我是没有兴趣的,所以我用了mpui.直接拷到/d/mplayer就好了.这个mplayer占用内存是少.我的播放DVD用了12M.加上MPUI一共17M.WMP可是占了30多M呢.微软的东东从来都是吃内存的大户
五、MPlayer的使用
1、命令行方式
上述我们编译好的Mplayer.exe是一个命令行的应用程序——事实上官方的windows realse也是命令行版本的。这个在Windows的命令提示符里面可以运行,好在Windows的命令提示符支持拖动,我们也就不用费力的一个字符一个字符的输入了。
如图,是Mplayer播放文件的正确命令,注意mplayer.exe和媒体文件路径之间有空格键。具体使用及控制键请参阅上面提到的官方文档。
2、图形界面方式。 世界各地的软件编写者们为MPlayer编写了大量的GUI,其中windows平台的也为数不少。你可以在这里查到它们的列表:http://www.mplayerhq.hu/homepage/design7/projects.html
其中,比较优秀的有:
(1)WinMPLauncher (http://chameleon.gazellevillage.com/~twerp...MPLauncher.html)
我一直用这个,使用简单,功能强劲,而且资源占用几乎可以忽略不计。缺点是没有进度条和播控按钮。如图。使用方法:解压后双击 WinMPLauncher.exe,选择我们的MPlayer.exe所在路径,确定后即可使用它作为前端来调用MPlayer.exe播放文件了。
(2)mplgui (http://www.mplayerhq.hu/homepage/design7/projects.html)
这个图形界面的优点是功能全, 它支持皮肤、拖动、进度条、一些基本图形控制按钮,列表播放等。但是我只找到了一种方法打开文件——拖动,而且没有打开URL的控制项。使用方法和上面的那个大同小异。不再赘述。
(3)MPlayerWIN(http://www.chronix.org/projects/mplayerwin/)
有不少性能选项,也还可以。
(4)MPlayer interface(http://home.freeuk.com/tom.nealon/mplayer.html)
总体上介绍的第1、3、4基本上是同类的——单纯的GUI,但是综合性能上来讲还是第一个比较强。
(5)MPUI(http://www-user.tu-chemnitz.de/~mfie/index.php?software=mpui)
最好的一定要留在最后说。 这个图形界面功能是最全的,但同时也是占用资源最高的。下载后只将里面的MPUI.exe和autorun.inf两个文件解压到你的MPlayer目录,双击MPUI.exe即可使用。
还有很多,就不一一列出了,大家可以自己尝试,选出自己喜欢的。
如图是自己编译好的MPlayer,使用WinMPLauncher 界面播放mms流媒体时的截屏。但是mplayer播放的图像抓不下来哪位大虾知道怎么抓告诉一声,谢了!
我编译的这个版本的资源占用情况:
1094kbps的xvid影片(外挂sub字幕)连上GUI三个进程(在9~21%之间):
原文地址 http://forums.mozine.cn/index.php?showtopic=124&mode=threaded
|
|
|
|
|
Android 的一些资源
|
Android的官方站点:
http://www.android.com/
AndroidSource的官方安装方法:
http://source.android.com/download
Android的中文站点:
http://www.androidin.com/
源代码包的相应联结地址:
http://www.androidin.com/android-2337-1-1.html
我们可以采用Android官方站点推荐方式来下载Android的源代码,也可以从Android中文站点直接下载源代码程序包,随后再更新和同步.
当采用Android官方推荐方式下载或者需要更新你的源代码时,都需要git工具支持,当你的系统没有安装git或者git版本过低时,建议从下面的地址更新到最新的git包.(Android要求git版本必须大于1.5.4)
http://git.or.cz/
给git自动升级的方式:
gitclonegit://git.kernel.org/pub/scm/git/git.git
如果采用下载源代码包的方式,下载并展开后,在.repo/repo目录下有同步执行的文件repo,你可以将其拷贝到你的PATH所在路径以备使用,例如/usr/bin等等.或者也可以从Android站点得到最新的repo文件并复制到PATH所在路径.
wgethttp://android.git.kernel.org/repo
源代码包解开后,其主目录下存在repo_sync.sh文件,其主要是执行reposync以实现和Android站点同步代码包的目的,当执行出错后将再一次运行reposync命令直到同步正常结束,但原文件包含错误,建议改成下面的程序:(原文件中少了一个空格)
#!/bin/bash
echo"============startreposync================="
reposync
while[$?=1];do
echo"============syncfailed,re-syncagain====="
sleep3
reposync
done
这样,运行shrepo_sync.sh就可以自动实现本地代码包的同步和更新动作了.
我在FedoraCore6上经过同步之后,du-h./mydroid,占用空间大约是2.1G
在kernel子目录下存放的就是Android的LinuxKernel了,通过和标准的Linux2.6.25Kernel的对比,我们可以发现,其主要增加了以下的内容:
1.基于ARM架构增加Gold-Fish平台,相应增加的目录如下:
kernel/arch/arm/mach-goldfish
kernel/include/asm-arm/arch-goldfish
Gold-Fish平台采用的是ARM926T CPU作为BaseBand处理器, 该CPU主频至少为200M HZ.
采用MSM7201A CPU(ARM 11)作为主CPU, 其主频为528M HZ.
2.增加了yaffs2FLASH文件系统,相应增加的目录为:
kernel/fs/yaffs2
实际上,Android包经过编译后生成的system.img和ramdisk.img文件就是yaffs2格式的包.
3.增加了Android的相关Driver,相应目录为:
kernel/drivers/android
主要分为:
AndroidIPC系统:Binder
Android日志系统:Logger
Android电源管理:Power
Android闹钟管理:Alarm
Android内存控制台:Ram_console
Android时钟控制的gpio:Timed_gpio
4.增加了switch处理,相应的目录为:
kernel/drivers/switch/
5.增加了一种新的共享内存处理方式,相应增加的文件为:
kernel/mm/ashmem.c
6.其他为Linux-2.6.25内核所做的补丁等等,例如BlueTooth,在此不做详细分析
另外GoldFish平台相关的驱动文件如下:
1.字符输出设备:
kernel/drivers/char/goldfish_tty.c
2.图象显示设备:(FrameBuffer)
kernel/drivers/video/goldfishfb.c
3.键盘输入设备:
kernel/drivers/input/keyboard/goldfish_events.c
4.RTC设备:(RealTimeClock)
kernel/drivers/rtc/rtc-goldfish.c
5.USBDevice设备:
kernel/drivers/usb/gadget/android_adb.c
6.SD卡设备:
kernel/drivers/mmc/host/goldfish.c
7.FLASH设备:
kernel/drivers/mtd/devices/goldfish_nand.c
kernel/drivers/mtd/devices/goldfish_nand_reg.h
8.LED设备:
kernel/drivers/leds/ledtrig-sleep.c
9.电源设备:
kernel/drivers/power/goldfish_battery.c
10.音频设备:
kernel/arch/arm/mach-goldfish/audio.c
11.电源管理:
kernel/arch/arm/mach-goldfish/pm.c
12.时钟管理:
kernel/arch/arm/mach-goldfish/timer.c
以上为Android内核的大致分析,希望能给有兴趣的人员以简单帮助。
http://neilwong.cublog.cn
|
|
|
|
|
madplay 一个很好用的mp3播放器
|
madplay 是linux上的一个开源mp3播放器,它利用libmad库进行mp3软解码,libmad是一个开源的高精度 MPEG 音频解码库,支持 MPEG-1(Layer I, Layer II 和 LayerIII(也就是
MP3)。libmad提供 24-bit 的 PCM 输出,完全是定点计算,非常适合没有浮点支持的平台上使用。使用 libmad 提供的一系列
API,就可以非常简单地实现 MP3 数据解码工作。在 libmad 的源代码文件目录下的 mad.h 文件中,可以看到绝大部分该库的数据结构和 API 等。
madplay基于libmad又做了一些扩展功能,比如将mp3格式转成别的音频格式如 wav等,又集成了libid3tag库进行mp3信息显示。
由于项目需要我将madplay修改并移植到我们的系统中,作为音频播放界面的后台解码程序。另在程序中加入了wav的解码,使得这套代码能播放mp3和wav两种音频文件,试听下来效果也不错。
|
|
|
|
|
png 图片的解码程序
|
png算法(利用libpng):
#ifndef png_jmpbuf #define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) #endif
#define PNG_BYTES_TO_CHECK (4)
typedef struct { ML_U8* pSrcData; ML_U32 totolSize; ML_U32 readSize; }ML_PNG_READ_S;
static void ml_png_warning(png_structp png_ptr, png_const_charp message) { ml_debugprintf("libpng warning: %s\n", message); }
static void ml_png_error(png_structp png_ptr, png_const_charp message) { ml_debugprintf("libpng error: %s\n", message); longjmp(png_ptr->jmpbuf, 1); }
static void ml_png_user_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { ML_PNG_READ_S* pImgReadCtrl; if(!png_ptr || !png_ptr->jmpbuf) return; pImgReadCtrl=(ML_PNG_READ_S*)png_get_io_ptr(png_ptr); if(!pImgReadCtrl) { // longjmp(png_ptr->jmpbuf, 1); return; } if(pImgReadCtrl->pSrcData) { if(pImgReadCtrl->readSize+length>pImgReadCtrl->totolSize) { // longjmp(png_ptr->jmpbuf, 1); ml_debugprintf("libpng read date outof memory\n"); return; } memcpy(data, pImgReadCtrl->pSrcData+pImgReadCtrl->readSize, length); pImgReadCtrl->readSize+=length; } }
ML_BOOL ml_png_decode (ML_U8* img_buf, ML_U32 img_size,IMG_PARA_S* pImgpara) { png_bytep* row_pointers=NULL; png_structp png_ptr = NULL; png_infop info_ptr; ML_PNG_READ_S userReadCtrl;
ML_U32 m_width ; ML_U32 m_height;
ML_U32 color_type; ML_U32 dwRead=0;
ML_U32 i=0,j=0; ML_BOOL bRet=FALSE;
ML_U8* pArrayRGB = 0;
ML_U32 channels=0; ML_U32 chan_offset;
if(!img_buf || img_size<MLMAX(1, PNG_BYTES_TO_CHECK)) return FALSE; if(png_sig_cmp(img_buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { return FALSE; } /* Initialize stuff */ png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) { return FALSE; } info_ptr=png_create_info_struct(png_ptr); if(!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return FALSE; } if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return FALSE;
}
png_set_error_fn(png_ptr, NULL, ml_png_error, ml_png_warning);
//png_init_io(png_ptr, fp);
userReadCtrl.pSrcData=img_buf; userReadCtrl.totolSize=img_size; userReadCtrl.readSize = 0; png_set_read_fn(png_ptr, &userReadCtrl, ml_png_user_read_fn);
png_set_sig_bytes(png_ptr,0/* PNG_BYTES_TO_CHECK*/); //由于是内存源,比对标志后不需要恢复当前文件指针, //所以一定要设置成零,不然会造成后续操作指针越界等错误。
//png_read_info(png_ptr, info_ptr);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);
m_width = png_get_image_width(png_ptr, info_ptr); m_height = png_get_image_height(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); pArrayRGB = (ML_U8*)ml_malloc(m_height*m_width*3); row_pointers = png_get_rows(png_ptr, info_ptr);
switch(info_ptr->color_type) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_PALETTE: channels = 1; break; case PNG_COLOR_TYPE_GRAY_ALPHA: channels = 2; break; case PNG_COLOR_TYPE_RGB: channels = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: channels = 4; break; default: longjmp(png_ptr->jmpbuf, 1); }
chan_offset = info_ptr->bit_depth >> 3;
//需将 16 bit depth 缩减成 8 bit 否则显示花屏 if (info_ptr->bit_depth > 8) { for( i = 0; i < m_height; i++) { for(j = 0; j < (channels * m_width); j ++) row_pointers[i][j] = row_pointers[i][j*chan_offset]; } }
if (color_type == PNG_COLOR_TYPE_RGB) { int pos = 0; for( i = 0; i < m_height; i++) { for(j = 0; j < (3 * m_width); j += 3) { pArrayRGB[pos++] = row_pointers[i][j]; // red pArrayRGB[pos++] = row_pointers[i][j+1]; // green pArrayRGB[pos++] = row_pointers[i][j+2]; // blue } } }
// rgb with opacity else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { int pos = 0; for( i = 0; i < m_height; i++) { for( j = 0; j < (4 * m_width); j += 4) { pArrayRGB[pos++] = row_pointers[i][j]; // red pArrayRGB[pos++] = row_pointers[i][j+1]; // green pArrayRGB[pos++] = row_pointers[i][j+2]; // blue //pArrayRGB[pos++] = row_pointers[i][j+3]; // alpha } } }
// 256 grey values else if (color_type == PNG_COLOR_TYPE_GRAY) { int pos = 0;
// get color values for( i = 0; i < m_height; i++) { for( j = 0; j < m_width; j++) { pArrayRGB[pos++] = row_pointers[i][j]; // red pArrayRGB[pos++] = row_pointers[i][j]; // green pArrayRGB[pos++] = row_pointers[i][j]; // blue //pArrayRGB[pos++] = 0; // alpha } } }
// 256 grey values with opacity else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { int pos = 0;
// get color values for( i = 0; i < m_height; i++) { for( j = 0; j < (2 * m_width); j += 2) { pArrayRGB[pos++] = row_pointers[i][j]; // blue pArrayRGB[pos++] = row_pointers[i][j]; // green pArrayRGB[pos++] = row_pointers[i][j]; // red //pArrayRGB[pos++] = row_pointers[i][j+1]; // alpha } } }
pImgpara->imgHeight = m_height; pImgpara->imgWidth = m_width; pImgpara->imgRgbData = pArrayRGB;
png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return TRUE; }
|
|
|
|
|
jpeg 图片解码算法
|
jpeg 算法(利用libjpeg解压):
typedef struct { struct jpeg_source_mgr pub; ML_U8 *img_buf; ML_U32 img_size; } ml_jpg_source_mgr;
typedef ml_jpg_source_mgr* ml_jpg_src_ptr; ml_jpg_source_mgr mlsrc;
static void ml_jpg_init_source(j_decompress_ptr cinfo) { /**do nothing*/ }
static void ml_jpg_skip_input_data(j_decompress_ptr cinfo, ML_S32 num_bytes) { ml_jpg_src_ptr src = (ml_jpg_src_ptr)cinfo->src; if(num_bytes > 0) { src->pub.next_input_byte += num_bytes; src->pub.bytes_in_buffer -= num_bytes; } }
static void ml_jpg_term_source(j_decompress_ptr cinfo) { ml_jpg_src_ptr src = (ml_jpg_src_ptr)cinfo->src; /**no work necessary here*/ }
static boolean ml_jpg_fill_input_buffer(j_decompress_ptr cinfo) { ml_jpg_src_ptr src = (ml_jpg_src_ptr)cinfo->src; if(src->img_buf) { src->pub.next_input_byte = src->img_buf; src->pub.bytes_in_buffer = src->img_size; src->img_buf = NULL; } return TRUE; }
static void jpeg_init_src(j_decompress_ptr cinfo, ML_U8* img_buf, ML_U32 img_size) { ml_jpg_src_ptr src = NULL; // if(cinfo->src == NULL) // cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(ml_jpg_source_mgr)); cinfo->src = (struct jpeg_source_mgr*)&mlsrc; src = (ml_jpg_src_ptr)cinfo->src; src->pub.init_source = ml_jpg_init_source; src->pub.skip_input_data = ml_jpg_skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; src->pub.term_source = ml_jpg_term_source; src->pub.fill_input_buffer = ml_jpg_fill_input_buffer; src->pub.bytes_in_buffer = 0; src->pub.next_input_byte = NULL; src->img_buf = img_buf; src->img_size = img_size;
}
static void exitErrorHandler(void *error) { //do nothing }
ML_BOOL ml_jpg_decode(ML_U8* img_buf, ML_U32 img_size,IMG_PARA_S* pImgpara) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; ML_U32 row_stride; JSAMPARRAY buffer; ML_U8 *src = NULL;
ML_U16 x,y; ML_U8* pArrayRGB = 0; cinfo.err = jpeg_std_error(&jerr);
jerr.error_exit = &exitErrorHandler;
jpeg_create_decompress(&cinfo); jpeg_init_src(&cinfo, img_buf, img_size); jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); if(!buffer) { jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return FALSE; }
pArrayRGB = (ML_U8*)ml_malloc(cinfo.output_height*cinfo.output_width*3); if(!pArrayRGB) { return FALSE; } while(cinfo.output_scanline < cinfo.output_height) { y = cinfo.output_scanline; jpeg_read_scanlines(&cinfo, (JSAMPARRAY)buffer, 1);
if(cinfo.output_components == 3) { for(x = 0, src = buffer[0]; x < cinfo.output_width; x++, src+=3) { ML_U32 index = (y*cinfo.output_width+x)*3;
pArrayRGB[index] = src[0]; pArrayRGB[index+1] = src[1]; pArrayRGB[index+2] = src[2];
} } else if(cinfo.output_components == 2) { for(x = 0, src = buffer[0]; x < cinfo.output_width; x++, src+=2) { ML_U16 col16 ; ML_U32 index = (y*cinfo.output_width+x)*3; col16 = src[0]+(src[1]<<8); pArrayRGB[index] = ((FRAME_RGB16TO32(col16))>>24)&0xff; pArrayRGB[index+1] = ((FRAME_RGB16TO32(col16))>>16)&0xff; pArrayRGB[index+2] = ((FRAME_RGB16TO32(col16))>>8)&0xff; } } else if(cinfo.output_components == 1) { for(x = 0, src = buffer[0]; x < cinfo.output_width; x++, src++) {
ML_U32 index = (y*cinfo.output_width+x)*3; pArrayRGB[index] = src[0]; pArrayRGB[index+1] = src[0]; pArrayRGB[index+2] = src[0]; } } else { break; }
} pImgpara->imgHeight = cinfo.output_height; pImgpara->imgWidth = cinfo.output_width; pImgpara->imgRgbData = pArrayRGB;
//error: jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return TRUE; }
|
|
|
|
|
bmp 图片的解码程序
|
最近在电子书上做了几种图片的软解码程序。这里把样例程序 记录一下,方便参考。(由于博客长度限制 分三篇发布)
程序实现 将图片内存(即先将图片文件读取到一片内存)解压成RGB的数组,解压后每个像素有三个字节分别存 R G B值。
typedef struct { ML_U32 imgWidth; //图片宽 ML_U32 imgHeight; //图片高 ML_U8 *imgRgbData; //解压后图片的rgb点阵 }IMG_PARA_S;
bmp算法:
__packed struct tagbmp_filehead_s { ML_U16 bfType; ML_U32 bfSize; ML_U16 bfReserved1; ML_U16 bfReserved2; ML_U32 bfOffBits; } packed_attribute;
typedef struct tagbmp_filehead_s bmp_filehead_s;
__packed struct tagbmp_infohead_s { ML_U32 biSize; ML_S32 biWidth; ML_S32 biHeight; ML_U16 biPlanes; ML_U16 biBitCount; ML_U32 biCompression; ML_U32 biSizeImage; ML_S32 biXPelsPerMeter; ML_S32 biYPelsPerMeter; ML_U32 biClrUsed; ML_U32 biClrImportant; }packed_attribute; typedef struct tagbmp_infohead_s bmp_infohead_s;
typedef struct { ML_U8 rgbBlue; ML_U8 rgbGreen; ML_U8 rgbRed; ML_U8 rgbReserved; } RGBQUAD;
bmp_filehead_s bf; bmp_infohead_s bi;
ML_BOOL ml_bmp_decode (ML_U8* img_buf, ML_U32 img_size,IMG_PARA_S* pImgpara) {
RGBQUAD *pPal; ML_U8 *pBmpData; ML_U16 bitDepth; ML_U32 numColors; ML_S32 i,j;
ML_U8 *pFileBuf = img_buf; ML_U8 *pArrayRGB = 0;
ml_memcpy((ML_U8*)&bf,pFileBuf,sizeof(bmp_filehead_s)); pFileBuf += sizeof(bmp_filehead_s); ml_memcpy((ML_U8*)&bi,pFileBuf,sizeof(bmp_infohead_s));
if(bi.biCompression!=0) { printf("bmp Compression not support\n"); return FALSE; //压缩格式不支持 } bitDepth = bi.biBitCount;
if(bi.biClrUsed!=0) { numColors=(ML_U32)bi.biClrUsed; } else { switch(bitDepth) { case 1: numColors=2; break; case 4: numColors=16; break; case 8: numColors=256; break; case 24: case 32: numColors=0; break; default: //16bit 暂时不支持 return FALSE; } } if(bf.bfOffBits!=(ML_U32)(numColors*sizeof(RGBQUAD)+sizeof(bmp_filehead_s) +sizeof(bmp_infohead_s))) { printf("Invalid color numbers!\n"); return FALSE; } pBmpData =(ML_U8*)(img_buf+bf.bfOffBits);
// bf.bfSize=sizeof(bmp_filehead_s)+sizeof(bmp_infohead_s)+numColors*sizeof(RGBQUAD)+ImgSize; pArrayRGB = (ML_U8*)ml_malloc(bi.biHeight*bi.biWidth*3); if(!pArrayRGB) { return FALSE; } if(numColors!=0) { int index1,index2; pPal = (RGBQUAD* )(img_buf+sizeof(bmp_filehead_s)+sizeof(bmp_infohead_s));
for ( i=0; i<bi.biHeight;i++) { for ( j=0; j<bi.biWidth; j++) { index1 = (bi.biHeight-i-1)*bi.biWidth+j; index2 = ((pBmpData[(index1*bitDepth)>>3])>> (((8/bitDepth) -1 - (index1 % (8/bitDepth)))*bitDepth))&((1<<bitDepth)-1); pArrayRGB[(i*bi.biWidth+j)*3] = pPal[index2].rgbRed; pArrayRGB[(i*bi.biWidth+j)*3+1] = pPal[index2].rgbGreen; pArrayRGB[(i*bi.biWidth+j)*3+2] = pPal[index2].rgbBlue;
} } } else { int index; int byteoff; // pFileBuf = img_buf+sizeof(bmp_filehead_s); // pImgData = (bmp_infohead_s*)pFileBuf; byteoff = bitDepth/8; // pRGB = (RGBQUAD* )((ML_U8*)pImgData + (ML_U32)sizeof(bmp_infohead_s)); for ( i=0; i<bi.biHeight;i++) { for ( j=0; j<bi.biWidth; j++) { index = ((bi.biHeight-i-1)*bi.biWidth+j)*byteoff; pArrayRGB[(i*bi.biWidth+j)*3] = pBmpData[index+2]; pArrayRGB[(i*bi.biWidth+j)*3+1] = pBmpData[index+1]; pArrayRGB[(i*bi.biWidth+j)*3+2] = pBmpData[index];
} } }
pImgpara->imgHeight = (ML_U16)bi.biHeight; pImgpara->imgWidth = (ML_U16)bi.biWidth; pImgpara->imgRgbData = pArrayRGB;
return TRUE;
}
|
|
|
|
|
ubuntu下让应用独占framebuffer显示
- []
|
linux上写了一个应用程序 显示用操作framebuffer方式实现。运行这样的应用程序有一个问题,即framebuffer 刷屏不是独占的 容易跟终端的其他显示输出相互干扰。
解决方法就是操作tty设备。原理很简单,就是打开一个新的终端tty设备,把它激活,并设为图形模式,让它独占framebuffer设备,然后再输出图形,这样,即使用户按Alt+Fi也无法切换终端,framebuffer就不会被重刷,从而实现了稳定的输出。
测试代码如下:
//kingmk added for this app occupy framebuffer alone { int vtnum, ttyfd; char ttystr[20]; /* open /dev/tty0 and get the vt number */ if ((ConsoleFd = open("/dev/tty0", O_WRONLY, 0)) < 0) { return; }
if (ioctl(ConsoleFd, VT_OPENQRY, &vtnum) < 0 || vtnum < 0) { return; }
close(ConsoleFd); ConsoleFd = -1; /* open the console tty */ sprintf(ttystr, "/dev/tty%d", vtnum); /* /dev/tty1-64 */ ConsoleFd = open(ttystr, O_RDWR | O_NDELAY, 0); if (ConsoleFd < 0) { return; }
/* save current vt number */ { struct vt_stat vts; if (ioctl(ConsoleFd, VT_GETSTATE, &vts) == 0) OldVT = vts.v_active; } /* disconnect from controlling tty */ ttyfd = open("/dev/tty", O_RDWR); if (ttyfd >= 0) { ioctl(ttyfd, TIOCNOTTY, 0); close(ttyfd); } /* some magic to restore the vt when we exit */ { struct vt_mode vt; if (ioctl(ConsoleFd, VT_ACTIVATE, vtnum) != 0) printf("ioctl VT_ACTIVATE\n"); if (ioctl(ConsoleFd, VT_WAITACTIVE, vtnum) != 0) printf("ioctl VT_WAITACTIVE\n"); if (ioctl(ConsoleFd, VT_GETMODE, &vt) < 0) { printf( "error: ioctl VT_GETMODE\n"); return; } vt.mode = VT_PROCESS; vt.relsig = SIGUSR1; vt.acqsig = SIGUSR1; if (ioctl(ConsoleFd, VT_SETMODE, &vt) < 0) { printf( "error: ioctl(VT_SETMODE) failed\n"); return; } }
/* go into graphics mode */ if (ioctl(ConsoleFd, KDSETMODE, KD_GRAPHICS) < 0) { printf( "error: ioctl(KDSETMODE, KD_GRAPHICS) failed\n"); return; } }
退出应用时:
{ struct vt_mode VT; /* restore text mode */ ioctl(ConsoleFd, KDSETMODE, KD_TEXT); /* set vt */ if (ioctl(ConsoleFd, VT_GETMODE, &VT) != -1) { VT.mode = VT_AUTO; ioctl(ConsoleFd, VT_SETMODE, &VT); } /* restore original vt */ if (OldVT >= 0) { ioctl(ConsoleFd, VT_ACTIVATE, OldVT); OldVT = -1; } close(ConsoleFd); }
|
|
|
|
|
automake 错误
|
虚拟机与windows 的共享目录下操作automake --add-missing 命令时会出现
installing `./install-sh'; error while making link 等错误
将代码目录cp到其他地方(非共享目录下)则操作正常。
用qmake 生成makefile 则没有问题。
|
|
|
|
|
VirtualBox+ubuntu
- []
|
环境:主机操作系统是Windows XP,虚拟机是Ubuntu 8.10,虚拟机是VirtualBox 2.1.0。
1. 安装增强功能包(Guest Additions)
安装好Ubuntu 8.10后,运行Ubuntu并登录。然后在VirtualBox的菜单里选择"设备(Devices)" -> "安装增强功能包(Install Guest Additions)"。
你会发现在Ubuntu桌面上多出一个光盘图标,这张光盘默认被自动加载到了文件夹/media/cdom0。进入命令行终端,输入:
cd /media/cdom0
sudo ./VboxLinuxAdditions.run
开始安装工具包。安装完毕后会提示要重启Ubuntu。
2. 设置共享文件夹
重启完成后点击"设备(Devices)" -> 共享文件夹(Shared Folders)菜单,添加一个共享文件夹,选项固定和临时是指该文件夹是否是持久的。共享名可以任取一个自己喜欢的,比如"gongxiang",尽量使用英文名称。
3. 挂载共享文件夹
重新进入虚拟Ubuntu,在命令行终端下输入:
sudo mkdir /mnt/shared
sudo mount -t vboxsf gongxiang /mnt/shared
其中"gongxiang"是之前创建的共享文件夹的名字。OK,现在Ubuntu和主机可以互传文件了。
假如您不想每一次都手动挂载,可以在/etc/fstab中添加一项
gongxiang /mnt/shared vboxsf rw,gid=100,uid=1000,auto 0 0
这样就能够自动挂载了。
4. 卸载的话使用下面的命令:
sudo umount -f /mnt/shared
注意:
/sbin/mount.vboxsf: mounting failed with the error: Protocol error
原因分析可以看Tips on running Sun Virtualbox的Shared Folder on a Linux Guest节。
|
|
|
|
|
ubuntu 的一些问题及解决
- []
|
1) 时区相差8个小时
修改时区可以用
sudo dpkg-reconfigure tzdata
设置为上海以后时间显示还是相差8个时区,需修改
/etc/default/rcS 文件,将 UTC=yes 改为 UTC=no
2)这次安装了ubuntu 后发现 ctrl+alt+fn 无法进入文本模式,不知道什么原因。但有时候我想在纯文本下测试 比如framebuffer的使用。没办法,只好硬来了,在终端运行runlevel 后显示 N2 ,即用2级启动。
进 /etc/rc2.d 移除S30gdm 文件
sudo mv /S30gdm K30gdm //这样系统启动时找不到gdm 不会进入图形界面,则进入文本模式。
(文本模式下 ctrl+alt+fn 组合键又起作用了,晕死。)输入 startx 可以进图形模式,图形模式下能正常使用终端 但无法用组合键切换到文本模式?估计是装了vmtool 后造成的问题。重新安装vmware tools 问题解决。
3)ubuntu8 正常情况下没有 /dev/fb0 设备文件,这样无法在程序中使用framebuffer 控制显示界面
vi /boot/grub/menu.lst
在每个kernel 行后加入 vga= 0x314(800x600 16bit) 重启后出现 /dev/fb0 文件,在终端编写一个程序 打开这个设备文件,发现不能正常打开 perror 提示权限错误。
sudo chmod 777 /dev/fb0
之后能正确打开,但在终端下对framebuffer 进行操作 比如刷一帧白屏没有反应,切换到文本模式下,程序可以正常工作。
4) 关机速度慢
sudo gedit /etc/init.d/alsa-utils 找到 mute_and_zero_levels "$TARGET_CARD" || EXITSTATUS=1 改为 #mute_and_zero_levels "$TARGET_CARD" || EXITSTATUS=1
重启即可
|
|
|
|
|
ubuntu下搭建C/C++开发环境
|
更新apt的源,测试下来台湾镜像速度是比较快的,2M带宽apt的速度基本能上200k 另据说大陆网易源也不错,没试过。
sudo cp /etc/apt/sources.list /etc/apt/sources.listbk
然后将以下内容替换到 /etc/apt/sources.list (我用的是ubuntu8.10)
## Uncomment the following two lines to add software from the 'backports' ## repository. ## N.B. software from this repository may not have been tested as ## extensively as that contained in the main release, although it includes ## newer versions of some applications which may provide useful features. ## Also, please note that software in backports WILL NOT receive any review ## or updates from the Ubuntu security team. # deb http://us.archive.ubuntu.com/ubuntu/ intrepid-backports main restricted universe multiverse # deb-src http://us.archive.ubuntu.com/ubuntu/ intrepid-backports main restricted universe multiverse
更新源列表以后输入 sudo apt-get update
然后可以安装所需要的软件了。
1)装基本开发环境 sudo apt-get install build-essential gcc make gdb
2)装编辑器 sudo apt-get install vim emacs
3)装基本开发库 sudo apt-get install libc6 libc6-dev
4)装manpage, 装了之后可以直接用 man 查阅各函数的详细用法 如 man opendir sudo apt-get install manpages-dev
5)装esvn版本管理器 sudo apt-get install esvn
可以选择安装一些集成开发环境 如eclipse kdevelop 等。
另外如需要makefile生成工具可以选择 automake qmake 等。
现在可以通过ubuntu 进行软件开发了。
|
|
|
|
|
windows7 终于可以工作了
|
想在windows7 系统上工作,对我来说以下几个软件是必要的:
1)vc 6.0 这个运行基本没有问题---比较奇怪的是如果将vc6.0的兼容模式改成:windows xp sp 2 或者以管理员身份运行时有问题。这两项都不要打勾就行了。
2)ads1.2 这个是arm编译器。安装一切正常,但运行时总会有莫名其妙的异常,兼容模式中选择:windows xp sp2,禁用桌面组件,以管理员身份运行之后就可以了。
3)VMware-workstation-7 + ubuntu 8.10
这里把虚拟机更新到7.0 比较好( 跟windows7无关),因为之前用vmware 5.6.x 时,ubuntu8 无法使用共享文件夹,当时因为没有找到破解的vm7.0以上版本,很费劲的用虚拟机的网络下载了一个高版本的vmtools才搞定。直接用vm7.0 就没有这些问题了。
4)程序阅读工具 UE,Source Insight 这些都能正常运行。
现在整体测试下来 性能还不错,T43终于正式退役了 哈哈。
|
|
|
|
|
Arm 系统中常用的段分类说明
- []
|
.text段是代码段。它用来放程序代码(code)。它通常是只读的。 .data段是数据段。它用来存放初始化了的(initailized)全局变量(global)和初始化了的静态变量(static)。它是可读可写的。 .bss段是全局变量数据段。它用来存放未初始化的(uninitailized)全局变量(global)和未初始化的静态变量(static)。它也是可读可写的。bss是英文Block Started by Symbol的缩写。之所以把bss跟data分开来,是因为系统会为这些bss段的变量的初值清零。 .rodata段是常量数据段。它用来存放常量(const)。它也是只读的。
在ARM的集成开发环境中, 1、只读的代码段称为Code段,即上述的.text段。 2、只读的常量数据段,被称作RO Data段,即上述的.constdata段。 以上两个段统称为RO段(Read Only),放在ROM或FLASH等非易失性器件中。 3、可读可写的初始化了的全局变量和静态变量段,被称作RW Data段(ReadWrite),即上述的.data段。 4、可读可写的未初始化的全局变量和静态变量段,被称作ZI Data段(Zero Init),即上述的.bss段。因为这个段里的变量要被初始化为零,所以叫ZI段。 以上两个段统称为RW段,而在运行时,它必须重新装载到可读可写的RAM中。
一 可执行文件组成及内存映射 在ADS下,可执行文件有两种,一种是.axf文件,带有调试信息,可供AXD调试工具使用.另一种是.bin 文件,可执行的二进制代码文件。我们重点是讲描.bin文件的组成。 我们把可执行文件分为两种情况:分别为存放态和运行态。 1. 存放态 存放态是指可执行文件通过fromelf产生后,在存储介质(flash或磁盘)上的分布. 此时可执行文件一 般由两部分组成:分别是代码段和数据段。代码段又分为可执行代码段(.text)和只读数据段(.rodata), 数据段又分为初始化数据段(.data)和未初始化数据段(.bss)。可执行文件的存放态如下: +-------------+----------- | .bss | +-------------+-- 数据段 | .data | +-------------+----------- | .rodata | |_____________| 代码段 | .text | +-------------+----------- 2. 运行态 可执行文件通过装载过程, 搬入到RAM中运行, 这时候可执行文件就变成运行态。在ADS下对可执行代 码各段有另一个名称: | ... | +-------------+----------- | .bss | ZI 段 +-------------+-- 数据段 | .data | RW 段 +-------------+----------- | .rodata | |_____________| 代码段(RO 段) | .text | +-------------+----------- | ... | 装载前 当可执行文件装载后, 在RAM中的分布如下: | ... | +-------------+-- ZI段结束地址 | ZI 段 | +-------------+-- ZI段起始地址 | 保留区2 | +-------------+-- RW段结束地址 | RW 段 | +-------------+-- RW段起始地址 | 保留区1 | +-------------+-- RO段结束地址 | RO 段 | +-------------+-- RO段起始地址 | ... | 装载后 所以装载过程必须完成把执行文件的各个段从存储介质上搬到RAM指定的位置。而这个装载过程由谁来完 成呢?由我们的启动程序来完成.
二 装载过程 在ADS中,可以通过两种方式来指定可执行代码各段在RAM中的位置,一个是用armlink来指定,一种是 用scatter文件来指定.RAM区的起始地址:0x30000000. 1. armlink指定代码段地址 我们通常的代码,只用指定两个段开始地址, RO段的起始地址和RW段的起始地址, ZI段紧接在RW段之 后.示例见该部分的1.1.3. 2. scatter指定代码段地址 我们也可以通过scatter文件指定可执行文件各段的详细地址. Scatter文件如下: MYLOADER 0x30000000 ;MYLOADER: 为可执行文件的名称, 可自定义 ;0x3000000: 起始地址 { RO 0x30000000 ;RO 只读代码段的名称 ;0x30000000: 只读代码段的起始地址 { init.o (Init, +First) ; Init代码段为可执行文件的第一部分. * (+RO) ;所有其它的代码段和只读数据段放在该部分 } RW +0 ;RW: RW段的名称 ;+0: 表示RW段紧接着RO段 { * (+RW) ;所有RW段放在该部分 } ZI +0 ;ZI: ZI段的名称 ;+0: 表示ZI段紧接着RW段 { *(+ZI) ;所有ZI段放在该部分 } } 3. ADS产生的各代码段宏 |Image$$RO$$Base| /* RO代码段起始地址 */ |Image$$RO$$Limit| /* RO 代码段结束地址 */ |Image$$RW$$Base| /* RW代码段起始地址 */ |Image$$RW$$Limit| /* RW 代码段结束地址 */ |Image$$ZI$$Base| /* ZI 代码段起始地址 */ |Image$$ZI$$Limit| /* ZI 代码段结束地址 */ 注意:在两个$$之间的名称, 与scatter中指定的段的名称相同. 4. 装载过程说明 当从NorFlash启动时, 要把flash芯片的首地址映射到0x00000000位置, 系统启动后, 启动程序本身把自己从 flash中搬到RAM中运行. 搬移后的各段起始地址, 由以上宏来确定. 当从NandFlash启动时, S3C2410会自动把前NandFlash的前4k搬到S3C2410的内部RAM中,并把内部 RAM的首地址设为0x00000000,CPU从0x00000000开始执行. 所以, 在nandFlash的前4k程序中,必须包含从 NandFlash把BootLoader的其余部分装入RAM的程序.
附:TI 编译中常用的段说明
系统常用的段定义:
.cinit:包含未用const声明的外部(external)或静态(static)数据表
.const:包含已用const声明的外部或静态数据表以及字符串常量。
.text:包含所有可执行的代码以及常量。
.bss:用于为cinit段以及未初始化的全局和静态变量保留空间(一般是内存空间)
|
|
|
分页共3页 1 2 3 下一页 最后一页
|