2010年5月28日 星期五

(轉載)Ubuntu 10.04 換成 sun-java-jdk 的步驟

ref: http://blog.cheyingwu.tw/index.php/2010/05/02/ubuntu-10-04-switch-to-sun-jdk/

話說沒讀 release notes 中地雷的人還蠻多的,我也是其中之一
在 ubuntu 10.04 預設是 openjdk 要換成 sun-java-jdk 也不是很難
首先先要加入 repository
sudo add-apt-repository "deb http://archive.canonical.com/ lucid partner"
然後安裝 sun-jdk
sudo apt-get update
sudo apt-get install sun-java6-jdk sun-java6-plugin
然後手動切換成 sun-jdk
sudo update-java-alternatives -s java-6-sun
這樣就可以換成 sun-jdk 了
話說沒讀 release notes 中地雷的人還蠻多的,我也是其中之一
在 ubuntu 10.04 預設是 openjdk 要換成 sun-java-jdk 也不是很難
首先先要加入 repository
sudo add-apt-repository 『deb http://archive.canonical.com/ lucid partner』
然後安裝 sun-jdk
sudo apt-get update
sudo apt-get install sun-java6-jdk sun-java6-plugin
然後手動切換成 sun-jdk
sudo update-java-alternatives -s java-6-sun
這樣就可以換成 sun-jdk 了

=========================================
順道一題,由於想要在ubuntu上安裝android的開發套件
所以需要安裝eclipse and ADT
之前第一次安裝的ubuntu是32位元版,沒碰到什麽問題
後來第二次安裝ubuntu時選擇安裝64位元版本, 結果在安裝ADT確遇到問題了(這邊有提供解法 http://developer.android.com/sdk/installing.html#troubleshooting)
為了省去麻煩, 建議還是安裝32位元版的ubuntu就好
不然後續可能要多作一些額外處理才能正常使用android開發環境

補充:要安裝Android開發套件,安裝完eclipse之後還要確定有安裝Eclipse Java development tools (JDT), 之後才能安裝ADT

2010年5月27日 星期四

Thinkpad Trackpoint Scrolling in ubuntu 10.04

轉錄 (http://psung.blogspot.com/2010/04/thinkpad-trackpoint-scrolling-in-ubuntu.html)

Thinkpad TrackPoint Scrolling in Ubuntu Lucid/10.04

Another Ubuntu release, another set of X.org shakeups.
Some things in X changed in Lucid (xorg 1:7.5+5 and higher), breaking existing Thinkpad TrackPoint scrolling configurations that modify files in /etc/hal/fdi/policy (like those you may have seen in this previous post). You can use gpointing-device-settings to apply the same policy, but I found that even that stops working after a suspend/resume cycle.
Samson Yeung pointed out to me the following fix which can be applied on Ubuntu Lucid/10.04:
Create a new file /usr/lib/X11/xorg.conf.d/20-thinkpad.conf with the following contents:
Section "InputClass"
    Identifier "Trackpoint Wheel Emulation"
    MatchProduct "TrackPoint"
    MatchDevicePath "/dev/input/event*"
    Driver "evdev"
    Option "EmulateWheel" "true"
    Option "EmulateWheelButton" "2"
    Option "Emulate3Buttons" "false"
    Option "XAxisMapping" "6 7"
    Option "YAxisMapping" "4 5"
EndSection
Then restart X.
This configuration seems to be general enough that it works for both Thinkpad laptops with TrackPoints and the Thinkpad TrackPoint keyboard.
Source: instructions derived from these instructions by Samson Yeung. Thanks, Samson!

2010年5月26日 星期三

mplayer video out driver (轉載)

在很多應用中的圖形輸出數據是存放在一些指定的內存區域的,比如說我現在實現的基於 minigui圖形中間件的mplayer播放器的,在播放前需要告訴mplayer當前播放窗口所在的內存地址和當前的屏幕像素深度,bpp,窗口大小等 等一系列的信息,這就有必要給mplayer寫個自己的video_out driver了。和大 多數驅動一樣,mplayer也提供了一個驅動函數結構體,其結構體定義如下(在libvo/video_out.h文件中定義):
typedef struct vo_functions_s{
 
vo_info_t *info;
 
/*
  
* Preinitializes driver (real INITIALIZATION)
  
* arg - currently it's vo_subdevice
  
* returns: zero on successful initialization, non-zero on error.
  
*/
 
int (*preinit)(const char *arg);
 
/*
 
* Initialize (means CONFIGURE) the display driver.
  
* params:
  
* width,height: image source size
  
* d_width,d_height: size of the requested window size, just a hint
  
* fullscreen: flag, 0=windowd 1=fullscreen, just a hint
  
* title: window title, if available
  
* format: fourcc of pixel format
  
* returns : zero on successful initialization, non-zero on error.
  
*/
 
int (*config)(uint32_t width, uint32_t height, uint32_t d_width,
 
uint32_t d_height, uint32_t fullscreen, char *title,
 
uint32_t format);

 
/*
  
* Control interface
  
*/
 
int (*control)(uint32_t request, void *data, ...);

 
/*
 
* Display a new RGB/BGR frame of the video to the screen.
 
* params:
 
* src[0] - pointer to the image
 
*/
 
int (*draw_frame)(uint8_t *src[]);

 
/*
  
* Draw a planar YUV slice to the buffer:
  
* params:
  
* src[3] = source image planes (Y,U,V)
  
* stride[3] = source image planes line widths (in bytes)
  
* w,h = width*height of area to be copied (in Y pixels)
  
* x,y = position at the destination image (in Y pixels)
  
*/
  
int (*draw_slice)(uint8_t *src[], int stride[], int w,int h, int x,int y);

  
/*
   
* Draws OSD to the screen buffer
   
*/
  
void (*draw_osd)(void);

  
/*
  
* Blit/Flip buffer to the screen. Must be called after each frame!
  
*/
  
void (*flip_page)(void);

  
/*
   
* This func is called after every frames to handle keyboard and
   
* other events. It's called in PAUSE mode too!
   
*/
   
void (*check_events)(void);

   
/*
    
* Closes driver. Should restore the original state of the system.
    
*/
   
void (*uninit)(void);
} vo_functions_t;
1:初始化驅動(preinit 函數、config函數和uninit 函數):當驅動初始化時將調用preinit ,退出時則調用uninit函數(注意:播放器在每播放一個媒體文件時都會初始化一次video驅動的)。在preinit函數和config函數里可以做我們一些初始化工作,比如指定存放音頻的內存地址,當前設備支持的像素,窗口大小,和 bpp(每像素點需要用多少bit存儲))等工作。而uninit 函數則可以做些收尾工作了....
2:告訴mplayer設備支持的圖形顯示格式在mplayer調用完preinit 函數後, 它就要開始輸出數據啦。它在輸出前 會去查詢下驅動支持的像素格式等一些大小,這時候它將調用驅動的control函數,並且傳遞VOCTRL_QUERY_FORMAT參數, 這時候我們就應該把preinit函數中設置的參數告訴mplayer,然後mplayer就按設備支持的 格式輸出數據,
3:獲取 mplayer圖形數據:獲取mplayer數據有很多種方法,這些方法可以根據設備來選擇,這裡我們只使用最簡單的方法VOCTRL_DRAW_IMAGE。同樣還是在control函數中,當mplayer輸出數據將會調用control函數並傳遞VOCTRL_DRAW_IMAGE參 數和mp_image_t指針,我們可以通過mp_image_t指針來獲取圖像數據的大小,存放的位置等必要信息,然後將這些存放在顯示內存中顯示出來...int dx = mpi->wint dy = mpi->huint8_t *buf = mpi->planes[0]int stride = mpi->stride[0]
4:其它:config 函數:mplayer將調用config函數來通知驅 動,mplayer顯示圖形的原始大小,和播放的最佳大小,和影片標題等信息,這些信息只是給驅動提供參考值的.還有其它draw_frame,draw_slice,draw_osd,flip_page等接口可以按需使用,充分利用 mplayer提供的接口可以打造一個性能較優的video_out驅動的。
5:結尾現在只是使用了簡單的mplayer驅動的方法,其實還有很多點可以去優化的,比如說讓mplayer直接將數據寫到顯示內存中,而 不再先放入mp_image_t結構體中,充分利用其它的幾個接口來提高驅動的性能。

mplayer音頻解碼分析

轉錄(http://dev.firnow.com/course/3_program/c++/cppjs/20090903/173578.html)
一.入口
    
main函數中的入口如下~  

/*======== PLAY AUDIO ===============*/  
if (mpctx->sh_audio)
    
if (!fill_audio_out_buffers())
    
// at eof, all audio at least written to ao
    
由mpctx->sh_audio引出,我想重 點強調一下sh_audio_t結構,這是音頻流頭部結構,要仔細看看(註釋也別放過)~  

// Stream headers: typedef struct {
  
int aid;
  
demux_stream_t *ds;
  
struct codecs_st *codec;
  
unsigned int format;
  
int initialized;
  
float stream_delay; // number of seconds stream should be delayed (according to dwStart or similar)
  
// output format:
  
int sample_format;
  
int samplerate;
  
int samplesize;
  
int channels;
  
int o_bps; // == samplerate*samplesize*channels (uncompr. bytes/sec)
  
int i_bps; // == bitrate (compressed bytes/sec)
  
// in buffers:
  
int audio_in_minsize; // max. compressed packet size (== min. in buffer size )
  
char* a_in_buffer;
  
int a_in_buffer_len;
  
int a_in_buffer_size;
  
// decoder buffers:
  
int audio_out_minsize; // max. uncompressed packet size (==min. out buffsize )
  
char* a_buffer;
  
int a_buffer_len;
  
int a_buffer_size;
  
// output buffers:
  
char* a_out_buffer;
  
int a_out_buffer_len;
  
int a_out_buffer_size;
  
struct af_stream_s *afilter; // the audio filter stream
  
struct ad_functions_s* ad_driver; #ifdef DYNAMIC_PLUGINS
  
void *dec_handle; #endif
  
// win32-compatible codec parameters:
  
AVIStreamHeader audio;
  
WAVEFORMATEX* wf;
  
// codec-specific:
  
void* context; // codec-specific stuff (usually HANDLE or struct pointer)
  
unsigned char* codecdata; // extra header data passed from demuxer to codec

  
int codecdata_len;
  
double pts; // last known pts value in output from decoder
  
int pts_bytes; // bytes output by decoder after last known pts
  
char* lang; // track language
  
int default_track; } sh_audio_t;
二.step by step 1.下面我們來分析 fill_audio_out_buffers()函數 static int fill_audio_out_buffers(void)
1.1查看音頻驅動有多大的空間可以填充解碼後的音頻 數據 bytes_to_write = mpctx->audio_out->get_space();
如果有空閒的空間,Mplayer會調用 ao->play()函數來填充這個buffer,並播放音頻數據。 這個音頻驅動的buffer的大小要設置合適,太小會 導致一幀圖像還沒播放完,buffer就已 經空了,會導致音視頻嚴重不同步;太大會導致 Mplayer需要不停地解析媒體文件來填充這 個音頻buffer,而視頻可能還來不及播放。
1.2 對音頻流進行解碼 if (decode_audio(sh_audio, playsize) < 0) 注:這裡的decode_audio只是一個接口,並 不是具體的解碼api。 這個函數從 sh_audio->a_out_buffer獲得至少playsize bytes的解碼或過濾後的音頻數據 ,成功返回0,失敗返回-1
1.3 將解碼後的音頻數據進行播放 playsize = mpctx->audio_out->play(sh_audio->a_out_buffer, playsize, playflags) ; 注:從 sh_audio->a_out_buffer中copy playsize bytes數據,注意這裡一定要copy出來, 因為當play調用後,這部分數據就會被覆蓋了。這些數據不一定要用完,返回的值是用掉 的數據長度。另外當 flags|AOPLAY_FINAL_CHUNK的值是真時,說明音頻文件快結束了。

1.4 if (playsize > 0) {
            
sh_audio->a_out_buffer_len -= playsize;
            
memmove(sh_audio->a_out_buffer, &sh_audio->a_out_buffer[playsize],
                    
sh_audio->a_out_buffer_len);
            
mpctx->delay += playback_speed*playsize/(double)ao_data.bps;
        
} 播放成功後就從 sh_audio->a_out_buffer中移出這段數據,同時減去 sh_audio->a_out_buffer_len 的長度

2.剛才說了,decode_audio()函數並不 是真正的解碼函數,它只是提供一個接口,下面我 們就來看看這個函數到底做了哪些事情 int decode_audio(sh_audio_t *sh_audio, int minlen)
2.1 解碼後的視頻數據都被cut成大小相同的一個個區間~
    
int unitsize = sh_audio->channels * sh_audio->samplesize * 16;
2.2 如果解碼器設置了audio_out_minsize,解碼可以等價於
    
while (output_len < target_len) output_len += audio_out_minsize; 因此我們必需保證a_buffer_size大於我們 需要的解碼數據長度加上audio_out_minsize, 所以我們最大解碼長度也就有瞭如下的限制:(是不是有 點繞口?~~)
    
int max_decode_len = sh_audio->a_buffer_size - sh_audio->audio_out_minsize ;
2.3 如果a_out_buffer中沒有我們需要的足夠多的解碼後數據,我們當然要繼續解碼撒~
只不過我們要注意,a_out_buffer中的數據 是經過filter過濾了的(長度發生了變化),這 裡會有一個過濾係數,我們反方向求過濾前的數據長度, 所以要除以這個係數。 while (sh_audio->a_out_buffer_len < minlen) {
        
int declen = (minlen - sh_audio->a_out_buffer_len) / filter_multiplier
            
+ (unitsize << 5); // some extra for possible filter buffering
        
declen -= declen % unitsize;
        
if (filter_n_bytes(sh_audio, declen) < 0)
            
return -1;
    
}

3.我們來看看這個filter_n_bytes函數 static int filter_n_bytes(sh_audio_t *sh, int len)
3.1 還記得我們剛才說的那個最大解碼長度嗎?這裡是要確保不會發生解碼後數據溢出。
assert(len-1 + sh->audio_out_minsize <= sh->a_buffer_size);
3.2 按需要解碼更多的數據
    
while (sh->a_buffer_len < len) {
        
unsigned char *buf = sh->a_buffer + sh->a_buffer_len;
        
int minlen = len - sh->a_buffer_len;
        
int maxlen = sh->a_buffer_size - sh->a_buffer_len;
        
//這裡才是調用之前確定的音頻解碼器進行真正音頻解 碼
        
int ret = sh->ad_driver->decode_audio(sh, buf, minlen, maxlen);
        
if (ret <= 0) {
            
error = -1;
            
len = sh->a_buffer_len;
            
break;
        
}
        
//解碼之後a_buffer_len增加
        
sh->a_buffer_len += ret;
    
}
3.3 在前面我們提到過過濾這個步驟,下面的圖描述了整個過程 filter_output = af_play(sh->afilter, &filter_input); 注:這裡實際上做的是過濾這部分的工作

    ------------                    ----------               ------------  
|        | 解碼|                    | 過濾|                  | 播放 
| 未解碼數據| ----->|解碼後數據| ------>| 播放的數據| ------>  
| a_in_buffer|              | a_buffer |          |a_out_buffer|
   ------------                     ----------                   ------------
3.4 if (sh->a_out_buffer_size < sh->a_out_buffer_len + filter_output->len) 注:如果過濾後的數據長度太長,需要擴展 a_out_buffer_size
3.5 將過濾後的數據從decoder buffer移除:
    
sh->a_buffer_len -= len;
    
memmove(sh->a_buffer, sh->a_buffer + len, sh->a_buffer_len);
三.結語
    
回顧一下今天的內容,我們從sh_audio_t結構 體出發,依次分析了fill_audio_out_b uffers()函數,decode_audio() 函數,filter_n_bytes()函數,但是並沒有分析具體的de code和play函數。
    
順便說點題外話,看Mplayer的代碼,結構化模塊 化的特點很突出,通常是先定義一組 接口,然後具體的程序去實現這些接口,這樣子對
代碼的維護和擴展都很有好處~

2010年5月25日 星期二

ubuntu熱鍵

Ctrl + N New 開新檔案
Ctrl + O Open 開啟舊檔
Ctrl + A Select all 全選
Ctrl + X Cut 剪下
Ctrl + C Copy 複製
Ctrl + V Paste 貼上
Ctrl + Z Undo 重來、上一步
Ctrl + Y Redo 復原(與上一 步相反功能)
Ctrl + S Save 儲存
Ctrl + W Close 關閉檔案
Ctrl + Q Quit 離開程式
Alt + Tab
切換視窗
Alt + Shift+Tab
反向切換視窗
Alt + Space
視窗控制選單
(與在視窗標題列案滑鼠右鍵同功能)
Alt + Print Screen
擷取目前視窗畫面
Ctrl + Alt + d
全部視窗最小化
Alt + F1
應用程式下拉選單
alt + 滑鼠左鍵
可以移動視窗
alt + 滑鼠中鍵
可以resize視窗
Ctrl + Alt + right arrow
切換桌面
Ctrl + Alt + left arrow
切換桌面
Ctrl + Alt + up arrow
切換桌面
Ctrl + Alt + down arrow
切換桌面
Ctrl + Alt + F1 = 跳到文字模式1(virtual terminals)
Ctrl + Alt + F2(F3)(F4)(F5)(F6) = 跳到文字模式2~6
Ctrl + Alt + F7 = 回到桌面
Ctrl + Alt + Backspace 跳出桌面,進入登入畫面

2010年5月24日 星期一

How to disable touchpad on ubuntu 9.10/10.04


If you want to disable your touchpad on Ubuntu 9.10/10.04 then issue the following commnad once:
gconftool-2 --type boolean --set /desktop/gnome/peripherals/mouse/touchpad_enabled false
Then to disable the touchpad issue the following command:
synclient TouchpadOff=1
This command is just active for the session so when you reboot your machine you will have to issue it again.  What I have done is to add it to my Startup Programs.  You will find Startup Programs under System|Preferences|Startup Applications.

2010年5月17日 星期一

建構ltrace for ARM

steps:
1. 從 http://packages.qa.debian.org/l/ltrace.html 下載ltrace source code (ltrace-0.5.3-2.tar.gz)
2. tar -zxv -f ltrace-0.5.3-2.tar.gz
3. ./configure --host=arm-linux CC=arm-linux-gcc LD=arm-linux-ld   ,  配置makefile
4. make
5. (可做可不做) arm-linux-strip ltrace  ,  縮減ltrace的size

完成, 之後就可以把strace copy到ARM 的 linux平台上執行了

2010年5月14日 星期五

建構strace for ARM

steps:
1. 從 http://sourceforge.net/projects/strace/files/strace/ 下載strace source code, 目前最新版為4.5.20 (strace-4.5.20.tar.bz2)
2. tar -jxv -f strace-4.5.20.tar.bz2
3. ./configure --host=arm-linux CC=arm-linux-gcc LD=arm-linux-ld   ,  配置makefile
4. make CFLAGS="-static"   , 產生靜態可執行檔
5. (可做可不做) arm-linux-strip strace  ,  縮減strace的size

完成, 之後就可以把strace copy到ARM 的 linux平台上執行了

2010年5月13日 星期四

在MinGW / MSYS環境下使用GDB Ctrl+C來突然中斷程式卻失敗的workaround

我是GDB的初學者,正確說Linux的環境其實都還不熟, 但公司整個開發環境都是以linux為base, 所以必須要熟析上面的開發工具, GDB就是其中一個, 因此我自己先在Windows系統上架設了仿Linux bash的環境也就是(MinGW + MSYS), 想要先在windows下執行程式並用GDB去debug trace, 藉此瞭解程式的運作和workflow, 但因為該程式是multi-thread的, 但我又不清楚整個運作流程, 所以想要先讓程式run一段時間後在中途中斷, 觀察一下thread的create情況, 但每次當我想要這樣做時(先用GDB 載入要trace的程式, 然後讓它執行一段時間) , 按下Ctrl+C想藉此中斷該程式, 每次這樣做都會讓整個程式停止並跳出執行, 根本無法順利的中途中斷它然後繼續使用GDB commands來一步一步trace. 這是前情提要

後來在網路上(經由Orson的幫忙搜尋) 找到了這個討論串GDB Ctrl-C Interrupt Fails WORKAROUND(http://cygwin.com/ml/cygwin/2006-06/msg00321.html), 自己動手try了一下, 確實可行耶, 雖然它是for cygwin的, 但在MinGW+MSYS下也是可以運作的, 差別是我compile該程式的方法省略掉了"-mno-cygwin", 也就是compile語法為
   gcc -o debugbreak.exe -mthreads debugbreak.c

以下我還是貼出那個討論串的程式內容

/* BEGIN debugbreak.c */

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif

#if _WIN32_WINNT < 0x0501
#error Must target Windows NT 5.0.1 or later for DebugBreakProcess
#endif

#include
#include
#include

/* Compile with this line:

gcc -o debugbreak -mno-cygwin -mthreads debugbreak.c

*/

static char errbuffer[256];

static const char *geterrstr(DWORD errcode)
{
    size_t skip = 0;
    DWORD chars;
    chars = FormatMessage(
    FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL, errcode, 0, errbuffer, sizeof(errbuffer)-1, 0);
    errbuffer[sizeof(errbuffer)-1] = 0;
    if (chars) {
        while (errbuffer[chars-1] == '\r' || errbuffer[chars-1] == '\n') {
            errbuffer[--chars] = 0;
        }
    }
    if (chars && errbuffer[chars-1] == '.') errbuffer[--chars] = 0;
    if (chars >= 2 && errbuffer[0] == '%' && errbuffer[1] >= '0' && errbuffer[1] <= '9')
    {
        skip = 2;
        while (chars > skip && errbuffer[skip] == ' ') ++skip;
        if (chars >= skip+2 && errbuffer[skip] == 'i' && errbuffer[skip+1] == 's')
        {
        skip += 2;
        while (chars > skip && errbuffer[skip] == ' ') ++skip;
        }
    }
    if (chars > skip && errbuffer[skip] >= 'A' && errbuffer[skip] <= 'Z') {
        errbuffer[skip] += 'a' - 'A';
    }
    return errbuffer+skip;
}

int main(int argc, char *argv[])
{
    HANDLE proc;
    unsigned proc_id = 0;
    BOOL break_result;

    if (argc != 2) {
        printf("Usage: debugbreak process_id_number\n");
        return 1;
    }
    proc_id = (unsigned) strtol(argv[1], NULL, 0);
    if (proc_id == 0) {
        printf("Invalid process id %u\n", proc_id);
        return 1;
    }
    proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)proc_id);
    if (proc == NULL) {
        DWORD lastError = GetLastError();
        printf("Failed to open process %u\n", proc_id);
        printf("Error code is %lu (%s)\n", (unsigned long)lastError,
            geterrstr(lastError));
        return 1;
    }
    break_result = DebugBreakProcess(proc);
    if (!break_result) {
        DWORD lastError = GetLastError();
        printf("Failed to debug break process %u\n", proc_id);
        printf("Error code is %lu (%s)\n", (unsigned long)lastError,
            geterrstr(lastError));
        CloseHandle(proc);
        return 1;
    }
    printf("DebugBreak sent successfully to process id %u\n", proc_id);
    CloseHandle(proc);
    return 0;
}

/* END debugbreak.c */