2011年1月13日 星期四

H.264 無法 Streaming 問題解決

問題:
H.264 的影片中的 ATOM (影片的 index) 被放在影片的最後面,因此需要將整個檔案下載完之後才能夠播放。

解決方法:
使用工具將 ATOM 移到影片的最前端,即可一邊下載一邊播放。

OpenSource 工具:
1.QTIndexSwapper (Adobe AIR application by Renaun Erickson)
2.qt-faststart (C application by Mike Melanson)


為避免 qt-faststart.c 斷頭,特別將 Source Code 貼於此。

/*
* qt-faststart.c, v0.1
* by Mike Melanson (mike at multimedia.cx)
* This file is placed in the public domain. Use the program however you
* see fit.
*
* This utility rearranges a Quicktime file such that the moov atom
* is in front of the data, thus facilitating network streaming.
*
* Compile this program using:
* cc qt-faststart.c -o qt-faststart
* Invoke the program with:
* qt-faststart
*
* Notes: Quicktime files can come in many configurations of top-level
* atoms. This utility stipulates that the very last atom in the file needs
* to be a moov atom. When given such a file, this utility will rearrange
* the top-level atoms by shifting the moov atom from the back of the file
* to the front, and patch the chunk offsets along the way. This utility
* presently only operates on uncompressed moov atoms.
*/

#include
#include
#include

#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])
#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \
(((uint8_t*)(x))[1] << 16) | \
(((uint8_t*)(x))[2] << 8) | \
((uint8_t*)(x))[3])
#define BE_64(x) (((uint64_t)(((uint8_t*)(x))[0]) << 56) | \
((uint64_t)(((uint8_t*)(x))[1]) << 48) | \
((uint64_t)(((uint8_t*)(x))[2]) << 40) | \
((uint64_t)(((uint8_t*)(x))[3]) << 32) | \
((uint64_t)(((uint8_t*)(x))[4]) << 24) | \
((uint64_t)(((uint8_t*)(x))[5]) << 16) | \
((uint64_t)(((uint8_t*)(x))[6]) << 8) | \
((uint64_t)((uint8_t*)(x))[7]))

#define BE_FOURCC( ch0, ch1, ch2, ch3 ) \
( (uint32_t)(unsigned char)(ch3) | \
( (uint32_t)(unsigned char)(ch2) << 8 ) | \
( (uint32_t)(unsigned char)(ch1) << 16 ) | \
( (uint32_t)(unsigned char)(ch0) << 24 ) )

#define QT_ATOM BE_FOURCC
/* top level atoms */
#define FREE_ATOM QT_ATOM('f', 'r', 'e', 'e')
#define JUNK_ATOM QT_ATOM('j', 'u', 'n', 'k')
#define MDAT_ATOM QT_ATOM('m', 'd', 'a', 't')
#define MOOV_ATOM QT_ATOM('m', 'o', 'o', 'v')
#define PNOT_ATOM QT_ATOM('p', 'n', 'o', 't')
#define SKIP_ATOM QT_ATOM('s', 'k', 'i', 'p')
#define WIDE_ATOM QT_ATOM('w', 'i', 'd', 'e')
#define PICT_ATOM QT_ATOM('P', 'I', 'C', 'T')
#define FTYP_ATOM QT_ATOM('f', 't', 'y', 'p')

#define CMOV_ATOM QT_ATOM('c', 'm', 'o', 'v')
#define STCO_ATOM QT_ATOM('s', 't', 'c', 'o')
#define CO64_ATOM QT_ATOM('c', 'o', '6', '4')

#define ATOM_PREAMBLE_SIZE 8
#define COPY_BUFFER_SIZE 1024

int main(int argc, char *argv[])
{
FILE *infile;
FILE *outfile;
unsigned char atom_bytes[ATOM_PREAMBLE_SIZE];
uint32_t atom_type = 0;
uint64_t atom_size;
uint64_t last_offset;
unsigned char *moov_atom;
uint64_t moov_atom_size;
uint64_t i, j;
uint32_t offset_count;
uint64_t current_offset;
unsigned char copy_buffer[COPY_BUFFER_SIZE];
int bytes_to_copy;

if (argc != 3) {
printf ("Usage: qt-faststart \n");
return 0;
}

infile = fopen(argv[1], "rb");
if (!infile) {
perror(argv[1]);
return 1;
}

/* traverse through the atoms in the file to make sure that 'moov' is
* at the end */
while (!feof(infile)) {
if (fread(atom_bytes, ATOM_PREAMBLE_SIZE, 1, infile) != 1) {
break;
}
atom_size = BE_32(&atom_bytes[0]);
atom_type = BE_32(&atom_bytes[4]);

if ((atom_type != FREE_ATOM) &&
(atom_type != JUNK_ATOM) &&
(atom_type != MDAT_ATOM) &&
(atom_type != MOOV_ATOM) &&
(atom_type != PNOT_ATOM) &&
(atom_type != SKIP_ATOM) &&
(atom_type != WIDE_ATOM) &&
(atom_type != PICT_ATOM) &&
(atom_type != FTYP_ATOM)) {
printf ("encountered non-QT top-level atom (is this a Quicktime file?)\n");
break;
}

/* 64-bit special case */
if (atom_size == 1) {
if (fread(atom_bytes, ATOM_PREAMBLE_SIZE, 1, infile) != 1) {
break;
}
atom_size = BE_64(&atom_bytes[0]);
fseek(infile, atom_size - ATOM_PREAMBLE_SIZE * 2, SEEK_CUR);
} else {
fseek(infile, atom_size - ATOM_PREAMBLE_SIZE, SEEK_CUR);
}
}

if (atom_type != MOOV_ATOM) {
printf ("last atom in file was not a moov atom\n");
fclose(infile);
return 0;
}

/* moov atom was, in fact, the last atom in the chunk; load the whole
* moov atom */
fseek(infile, -atom_size, SEEK_END);
last_offset = (uint64_t)ftell(infile);
moov_atom_size = atom_size;
moov_atom = malloc(moov_atom_size);
if (!moov_atom) {
printf ("could not allocate 0x%llX byte for moov atom\n",
atom_size);
fclose(infile);
return 1;
}
if (fread(moov_atom, atom_size, 1, infile) != 1) {
perror(argv[1]);
free(moov_atom);
fclose(infile);
return 1;
}

/* this utility does not support compressed atoms yet, so disqualify
* files with compressed QT atoms */
if (BE_32(&moov_atom[12]) == CMOV_ATOM) {
printf ("this utility does not support compressed moov atoms yet\n");
free(moov_atom);
fclose(infile);
return 1;
}

/* close; will be re-opened later */
fclose(infile);

/* crawl through the moov chunk in search of stco or co64 atoms */
for (i = 4; i < moov_atom_size - 4; i++) {
atom_type = BE_32(&moov_atom[i]);
if (atom_type == STCO_ATOM) {
printf (" patching stco atom...\n");
atom_size = BE_32(&moov_atom[i - 4]);
if (i + atom_size - 4 > moov_atom_size) {
printf (" bad atom size\n");
free(moov_atom);
return 1;
}
offset_count = BE_32(&moov_atom[i + 8]);
for (j = 0; j < offset_count; j++) {
current_offset = BE_32(&moov_atom[i + 12 + j * 4]);
current_offset += moov_atom_size;
moov_atom[i + 12 + j * 4 + 0] = (current_offset >> 24) & 0xFF;
moov_atom[i + 12 + j * 4 + 1] = (current_offset >> 16) & 0xFF;
moov_atom[i + 12 + j * 4 + 2] = (current_offset >> 8) & 0xFF;
moov_atom[i + 12 + j * 4 + 3] = (current_offset >> 0) & 0xFF;
}
i += atom_size - 4;
} else if (atom_type == CO64_ATOM) {
printf (" patching co64 atom...\n");
atom_size = BE_32(&moov_atom[i - 4]);
if (i + atom_size - 4 > moov_atom_size) {
printf (" bad atom size\n");
free(moov_atom);
return 1;
}
offset_count = BE_32(&moov_atom[i + 8]);
for (j = 0; j < offset_count; j++) {
current_offset = BE_64(&moov_atom[i + 12 + j * 8]);
current_offset += moov_atom_size;
moov_atom[i + 12 + j * 8 + 0] = (current_offset >> 56) & 0xFF;
moov_atom[i + 12 + j * 8 + 1] = (current_offset >> 48) & 0xFF;
moov_atom[i + 12 + j * 8 + 2] = (current_offset >> 40) & 0xFF;
moov_atom[i + 12 + j * 8 + 3] = (current_offset >> 32) & 0xFF;
moov_atom[i + 12 + j * 8 + 4] = (current_offset >> 24) & 0xFF;
moov_atom[i + 12 + j * 8 + 5] = (current_offset >> 16) & 0xFF;
moov_atom[i + 12 + j * 8 + 6] = (current_offset >> 8) & 0xFF;
moov_atom[i + 12 + j * 8 + 7] = (current_offset >> 0) & 0xFF;
}
i += atom_size - 4;
}
}

/* re-open the input file and open the output file */
infile = fopen(argv[1], "rb");
if (!infile) {
perror(argv[1]);
free(moov_atom);
return 1;
}
outfile = fopen(argv[2], "wb");
if (!outfile) {
perror(argv[2]);
fclose(outfile);
free(moov_atom);
return 1;
}

/* dump the new moov atom */
printf (" writing moov atom...\n");
if (fwrite(moov_atom, moov_atom_size, 1, outfile) != 1) {
perror(argv[2]);
goto error_out;
}

/* copy the remainder of the infile, from offset 0 -> last_offset - 1 */
printf (" copying rest of file...\n");
while (last_offset) {
if (last_offset > COPY_BUFFER_SIZE)
bytes_to_copy = COPY_BUFFER_SIZE;
else
bytes_to_copy = last_offset;

if (fread(copy_buffer, bytes_to_copy, 1, infile) != 1) {
perror(argv[1]);
goto error_out;
}
if (fwrite(copy_buffer, bytes_to_copy, 1, outfile) != 1) {
perror(argv[2]);
goto error_out;
}

last_offset -= bytes_to_copy;
}

fclose(infile);
fclose(outfile);
free(moov_atom);

return 0;

error_out:
fclose(infile);
fclose(outfile);
free(moov_atom);
return 1;
}


2010年12月28日 星期二

vim 16 進位顯示

16 進位顯示

:%! xxd


切換回正常顯示

:%! xxd -r


2010年11月12日 星期五

流浪者之歌

人生就是不停畫著同心圓沙圈
一圈一圈擴大心的體驗

而你們
就是我願裡的沙
為我舉起刻骨的痕


2010年7月19日 星期一

測試 UDP Port 狀態

FreeBSD 需由 ports 安裝 nmap


nmap -p PORT -sU -P0 IP


結果:

[root@XXX] ~# nmap -p 1812 -sU -P0 127.0.0.1

Starting Nmap 5.21 ( http://nmap.org ) at 2010-07-19 17:22 CST
Nmap scan report for localhost (127.0.0.1)
Host is up (1.0s latency).
PORT STATE SERVICE
1812/udp open radius

Nmap done: 1 IP address (1 host up) scanned in 2.11 seconds
[root@XXX] ~# nmap -p 1815 -sU -P0 127.0.0.1

Starting Nmap 5.21 ( http://nmap.org ) at 2010-07-19 17:22 CST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00051s latency).
PORT STATE SERVICE
1815/udp closed unknown

Nmap done: 1 IP address (1 host up) scanned in 1.19 seconds


2010年6月28日 星期一

Perl 取代並寫回目標檔案內容

取代前 target.txt 內容

123abc
456abc


執行

perl -pi -e 's/abc$//g' target.txt


取代後 target.txt 內容

123
456





取代前 code.txt 內容

function abc()
{
echo('abc');
}

function def(){ echo('def'); }


執行

perl -pi -e 's/^(function )([a-z])/$1.uc($2)/eg' code.txt


取代後 code.txt 內容

function Abc()
{
echo('abc');
}

function Def(){ echo('def'); }



備註:
-p 是單行比對模式。
若需要多行比對,請增加 -0777 參數,此參數的意義為「將讀取分隔符號從 \n 變成 undef」,等同於等個檔案內容一次讀入做處理。多行比對同時需要加上 s 修飾字。


2010年6月14日 星期一

約定?

「那約定怎麼辦?」我說。

「你瞭解我的,那只是一時昏頭」她回。
「真是多虧了那一句話點醒我」
「那些問題你能解決嗎?」

「再說吧」
我瞇著淚眼笑。


你懂

想著
想著
想著一切

總覺得飄渺

或許
在那踏實的背後
躲著一股
小小鼻酸

只有
你懂


不悔

叮啷一聲
果汁店收銀機驚醒了我的渾沌

難道
這竟是他們戲稱的
賺那買藥錢

怎麼我會在這兒
只為那
不悔的十年之約

為她摘下星星


2010年6月1日 星期二

美味咖哩作法

1.大蒜、洋蔥 炒至褐色軟透
2.加水後倒入果汁機
3.加入切碎的 胡蘿蔔 一起打碎
4.倒回鍋中,加入 馬鈴薯 與 辣椒,煮 20分鐘
5.取出 馬鈴薯 與 辣椒,過篩後倒回鍋中
6.放涼湯汁
7.加入 咖哩塊、奶油 與 砂糖煮化
8.肉煎過,加入鍋中熬煮 2小時,放置一晚自然涼(或肉煎熟後直接放入醬汁中食用)


2010年5月24日 星期一

憂傷瞬間

淡淡地憂傷
我感覺到

臉頰上的涼意 是蒸發中的悲傷
心裡曾經的裂痕 無聲地淌出了熔岩
滾燙著吞噬掉唯一的幸福

只剩一片孤寂的煙
飄散在下午 2點 39分的面前