FFMPEG 硬件解碼

原文地址:http://blog.csdn.net/yipie/article/details/7912291

摘要:對FFmpeg多媒體解決方案中的視頻編解碼流程進(jìn)行研究。結(jié)合對S3C6410處理器視頻硬件編解碼方法的分析呐馆,闡述了嵌入式Linux下基于FFmpeg的H.264視頻硬件編解碼在S3C6410處理器上的實(shí)現(xiàn)方法肥缔,為嵌入式多媒體開發(fā)提供參考。

引言

目前汹来,智能手機(jī)续膳、PDA和平板電腦等越來越多的嵌入式設(shè)備支持高清視頻采集和播放功能,高清視頻的采集或播放功能正廣泛用于游戲設(shè)備、監(jiān)控設(shè)備收班、視頻會議設(shè)備和數(shù)字網(wǎng)絡(luò)電視等嵌入式系統(tǒng)中姑宽。這些功能的實(shí)現(xiàn)建立在高性能視頻硬件編解碼技術(shù)基礎(chǔ)之上。本文闡述了基于FFmpeg的H.264視頻硬件編解碼在S3C6410處理器上的實(shí)現(xiàn)方法,為數(shù)字娛樂闺阱、視頻監(jiān)控和視頻通信系統(tǒng)開發(fā)過程中的高清視頻硬件編解碼的實(shí)現(xiàn)提供參考炮车。

FFmpeg[1]是一個開源免費(fèi)跨平臺的視頻和音頻流方案,屬于自由軟件酣溃。它包含非常先進(jìn)的音頻/視頻編解碼庫libavcodec瘦穆,提供了錄制、轉(zhuǎn)換以及流化音視頻的完整解決方案赊豌。FFmpeg支持MPEG4扛或、FLV等40多種編碼,以及AVI碘饼、ASF等90多種解碼熙兔。目前國內(nèi)較為流行的播放器暴風(fēng)影音和國外較為流行的Mplayer在音頻/視頻編解碼方面都用到了FFmpeg悲伶。

S3C6410[2]是三星公司推出的應(yīng)用處理器芯片,基于ARM11架構(gòu)住涉,主頻最高可達(dá)800 MHz麸锉。它具有多媒體硬件加速功能,其中包括大于30 fps的MPEG4SP舆声、H.264/263 BP和VC1(WMV9)多種視頻硬件編解碼花沉,可用于手機(jī)、平板電腦和游戲機(jī)等手持移動設(shè)備和其他高性能嵌入式設(shè)備媳握。國產(chǎn)手機(jī)魅族M8的處理器使用的就是S3C6410碱屁。

雖然FFmpeg提供了簡單的應(yīng)用程序編程接口(API),可以很方便地實(shí)現(xiàn)多種格式的視頻軟件編解碼[3]蛾找,但是軟件編解碼在處理復(fù)雜視頻編解碼(如H.264)時無法運(yùn)用到處理速度不快娩脾、內(nèi)存空間不多的嵌入式環(huán)境中。為了在資源有限的嵌入式環(huán)境下使用FFmpeg實(shí)現(xiàn)復(fù)雜視頻編解碼打毛,下面在分析FFmpeg視頻編碼流程和S3C6410處理器視頻編解碼方法的基礎(chǔ)上柿赊,闡述嵌入式linux操作系統(tǒng)下基于FFmpeg的H.264硬件編解碼在S3C6410處理器上的實(shí)現(xiàn)方法。

1 FFmpeg視頻編解碼流程

FFmpeg主要有encode/decode隘冲、muxer/demuxer和內(nèi)存操作3個模塊闹瞧。encode/decode模塊用于音視頻的編碼和解碼,存放在libavcodec子目錄中绑雄;muxer/demuxer模塊用于音頻和視頻的合并與分離(也稱混合器模塊)展辞,存放在libavformat目錄中;內(nèi)存等常用模塊存放于libavutil目錄中万牺。下面以解碼過程為例分析FFmpeg視頻編解碼流程罗珍。

解碼基本流程共分4步:

① 注冊所有可能用到的編解碼器和混合器。av_register_all(void)函數(shù)中通過執(zhí)行 REGISTER_MUXDEMUX(X,x)和REGISTER_ENCDEC(X,x)脚粟,把所有FFmpeg支持的混合器和編解碼器相關(guān)信息以鏈?zhǔn)降慕Y(jié)構(gòu)存放在內(nèi)存中覆旱。

② 打開視頻文件。av_open_input_file(AVFormatContext **ic_ptr,const char

*filename,AVInputFormat *fmt,int buf_size,AVFormatParameters

*ap)函數(shù)中偵測文件的格式核无,根據(jù)文件格式從鏈?zhǔn)降幕旌掀髦姓业较鄬?yīng)的混合器(demuxer)并分離出視頻信息扣唱。

③ 獲取視頻信息。通過av_find_stream_info(AVFormatContext

*ic)函數(shù)獲取視頻格式团南。根據(jù)視頻格式噪沙,在鏈?zhǔn)降囊曨l解碼器中找到相應(yīng)的視頻解碼器,并通過avcodec_open(AVCodecContext

*avctx,AVCodec *codec)函數(shù)將解碼器打開用于下一步視頻的解碼吐根。

④ 解碼一幀視頻正歼,通過 avcodec_decode_video(AVCodecContext *avctx,AVFrame

*picture,int *got_picture_ptr,const uint8_t *buf,int buf_size)函數(shù)解碼一幀視頻。

FFmpeg的編碼過程與解碼過程類似拷橘,不同的是第3步根據(jù)要求編碼的格式在鏈?zhǔn)降囊曨l編碼器中找到相應(yīng)的視頻編碼器局义,并執(zhí)行編碼過程喜爷。

通過以上對FFmpeg視頻編解碼流程分析可以知道,為了在FFmpeg中添加自定義的視頻編解碼器萄唇,并在程序運(yùn)行時使用這個編解碼器檩帐,關(guān)鍵在于如下兩點(diǎn):

① 根據(jù)FFmpeg對編解碼器的描述,實(shí)現(xiàn)自定義編解碼器穷绵。

② 通過REGISTER_ENCDEC(X,x)函數(shù)將自定義的視頻編解碼器添加到視頻編解碼器鏈中轿塔。在獲取視頻信息時,保證需要編碼或解碼的視頻能找到視頻編解碼器鏈中自定義的視頻編解碼器仲墨。

2 S3C6410處理器視頻編解碼方法

S3C6410視頻編解碼軟件架構(gòu)[4]如圖1所示勾缭。底層為操作系統(tǒng)空間,上層為用戶空間目养,視頻編解碼器通過驅(qū)動和操作系統(tǒng)以設(shè)備文件的形式使用俩由,使用的方法和普通文件一樣,包括文件打開和關(guān)閉癌蚁、文件讀寫和輸入/輸出控制(ioctl,input/output

control)幻梯。

圖1 S3C6410視頻編解碼軟件架構(gòu)

具體操作方法如下:

① 通過open函數(shù)打開編解碼器設(shè)備文件;

② 使用mmap方法在用戶空間和驅(qū)動空間之間映射輸入/輸出緩存空間努释,這樣做的好處是可以快速進(jìn)行數(shù)據(jù)輸入/輸出碘梢;

③ 通過ioctl設(shè)備編解碼參數(shù),初始化編解碼器伐蒂;

④ 輸入數(shù)據(jù)煞躬,通過ioctl執(zhí)行編解碼過程,輸出數(shù)據(jù)逸邦;

⑤ 通過close方法關(guān)閉編解碼器設(shè)備文件恩沛。

值得注意的是,無論編碼還是解碼缕减,處理的數(shù)據(jù)都是以一幀幀的形式操作的雷客,所以第4步是一個不斷循環(huán)的過程,直到所有數(shù)據(jù)處理完成桥狡。另外搅裙,雖然編解碼器以設(shè)備文件的形式使用,但是它不能使用標(biāo)準(zhǔn)的文件讀寫操作裹芝,查看編解碼的設(shè)備驅(qū)動可以發(fā)現(xiàn)部逮,其文件讀寫函數(shù)是空的,這一點(diǎn)三星公司的開發(fā)文檔并沒有說明局雄。

3 H.264硬件編解碼實(shí)現(xiàn)

FFmpeg的H.264硬件編解碼[5]實(shí)現(xiàn)就是自定義一個視頻編解碼器甥啄,加入到FFmpeg庫中。這個視頻編解碼器使用S3C6410處理視頻硬件編解碼功能來實(shí)現(xiàn)H.264的視頻編碼和解碼過程炬搭,這樣使用FFmpeg庫的多媒體程序可以用訪問FFmpeg其他編解碼器一樣的方法使用這個自定義的編解碼器蜈漓。添加自定義編解碼器的關(guān)鍵是根據(jù)FFmpeg中對編解碼的描述定義編解碼器穆桂,并實(shí)現(xiàn)定義中的相關(guān)函數(shù)。

在libavcodec/avcodec.h中的AVCodec結(jié)構(gòu)體是定義FFmpeg編解碼器的關(guān)鍵結(jié)構(gòu)體融虽,包括編解碼器的名字享完、類型(聲音/視頻)、編解碼器的識別號(CodecID)有额、支持格式和一些用于初始化般又、編碼、解碼和關(guān)閉的函數(shù)指針巍佑。

typedef struct AVCodec {

const char *name;

enum CodecType type;

enum CodecID id;

int priv_data_size;

int (*init)(AVCodecContext *);

int (*encode)(AVCodecContext *,uint8_t *buf,int buf_size,void *data);

int (*close)(AVCodecContext *);

int (*decode)(AVCodecContext *,void *outdata,int *outdata_size,

uint8_t *buf,int buf_size);

int capabilities;

struct AVCodec *next;

void (*flush)(AVCodecContext *);

const AVRational *supported_framerates;

const enum PixelFormat *pix_fmts;

} AVCodec;

H.264硬件編解碼器定義如下:

AVCodec s3cx264_encoder = {

.name="s3cx264",

.type=AVMEDIA_TYPE_VIDEO,

.id=CODEC_ID_H264,

.init=X264_init,

.encode=X264_frame,

.decode=X264_decode,

.close=X264_close,

};

解碼器的名字為s3cx264茴迁,類型為視頻。CodecID為H264萤衰,表示這個解碼器用于H.264視頻編解碼堕义。初始化、編碼脆栋、解碼和關(guān)閉函數(shù)指針分別指向X264_init倦卖、X264_frame、X264_decodec和X264_close函數(shù)椿争。

添加s3cx264編解碼器到編解器鏈中怕膛,關(guān)鍵是通過修改libavcodec/allcodecs.c文件實(shí)現(xiàn),修改如下:

REGISTER_ENCDEC (ASV1,asv1);

REGISTER_ENCDEC (S3CX264,s3cx264);

//添加s3cx264編解碼器

REGISTER_ENCDEC (ASV2,asv2);

這樣秦踪,在程序運(yùn)行時調(diào)用av_register_all(void)函數(shù)后褐捻,就可以把自定義的編解碼器s3cx264添加到FFmpeg存放在內(nèi)存中的解編碼器鏈中。值得提出的是洋侨,對同一個視頻格式FFmpeg有多個編解碼器與之相對應(yīng)舍扰。如H.264格式的視頻,F(xiàn)Fmpeg本身就帶有對應(yīng)的軟解碼器,現(xiàn)在添加了硬解碼器汽摹,為了避免不確定是哪一個解碼器在執(zhí)行成榜,可以把自定義的硬件編解碼器在注冊時放在注冊過程的最前面,這樣編解碼器在添加到解編器鏈中時就會放在靠前的位置,查找時就可以優(yōu)于軟件解碼器找到硬解碼器铺坞。

把硬件編解碼器s3cx264注冊到編解碼器鏈后,還要完成X264_init、X264_frame聊疲、X264_decodec和X264_close函數(shù),編解碼器才能正常工作沪悲。以下結(jié)合前面對S3C6410視頻編解碼過程的分析获洲,以編碼為例詳細(xì)闡述實(shí)現(xiàn)過程。

定義X264Context結(jié)構(gòu)體殿如,保存設(shè)備文件描述符贡珊、編碼參數(shù)和輸入/輸出地址等信息最爬,用于FFmpeg模塊間數(shù)據(jù)的傳遞:

typedef struct X264Context {

int dev_fd;

uint8_t *addr;

s3c_mfc_enc_init_arg_t enc_init;

s3c_mfc_enc_exe_arg_t enc_exe;

s3c_mfc_get_buf_addr_arg_t get_buf_addr;

uint8_t *in_buf,*out_buf;

AVFrame out_pic;

} X264Context;

X264_init實(shí)現(xiàn)的是編碼器初始化過程, 用于編碼器設(shè)備文件的打開门岔、內(nèi)存空間的映射爱致、編碼參數(shù)設(shè)置和獲取編解碼數(shù)據(jù)輸入/輸出地址。

static av_cold int X264_init(AVCodecContext *avctx){

X264Context *x4 = avctx>priv_data;

//打開編碼器設(shè)備文件

x4>dev_fd = open(MFC_DEV_NAME,O_RDWR|O_NDELAY);

//內(nèi)存空間映射

x4>addr = (uint8_t *) mmap(0,BUF_SIZE,PROT_READ |PROT_WRITE,MAP_SHARED,x4>dev_fd,0);

//編碼參數(shù)設(shè)置

ioctl(x4>dev_fd,S3C_MFC_IOCTL_MFC_H264_ENC_INIT,&x4>enc_init);

//獲取輸入/輸出地址

x4>get_buf_addr.in_usr_data = (int)x4>addr;

ioctl(x4>dev_fd,S3C_MFC_IOCTL_MFC_GET_YUV_BUF_ADDR,&x4>get_buf_addr)寒随;

x4>in_buf = (uint8_t *)x4>get_buf_addr.out_buf_addr;

x4>get_buf_addr.in_usr_data = (int)x4>addr;

ioctl(x4>dev_fd,S3C_MFC_IOCTL_MFC_GET_LINE_BUF_ADDR,&x4>get_buf_addr)糠悯;

x4>out_buf = (uint8_t *)x4>get_buf_addr.out_buf_addr;

return 0;

}

ioctl的參數(shù)為S3C_MFC_IOCTL_MFC_H264_ENC_INIT,表示使用H.264編碼妻往。

X264_frame函數(shù)執(zhí)行編碼過程互艾。需要注意的是data參數(shù)保存了需要編碼的數(shù)據(jù),是一個四維的數(shù)組讯泣,要把它轉(zhuǎn)換成一維數(shù)組用于S3C6410編碼器輸入忘朝。另外,編碼數(shù)據(jù)存在空的情況判帮,也就是空幀局嘁。這是需要處理的,方法是返回“0”,表示沒有輸出數(shù)據(jù)晦墙,否則程序運(yùn)行時會出現(xiàn)段錯誤悦昵。

static int X264_frame(AVCodecContext *ctx,uint8_t *buf,int bufsize,void *data){

……

//空間轉(zhuǎn)換

if(frame){

memcpy(x4>in_buf,frame>data[0],ctx>width*ctx>height);

memcpy(x4>in_buf+ctx>width*ctx>height,frame>data[1],ctx>width*ctx>height/4);

memcpy(x4>in_buf+ctx>width*ctx>height+ctx>width*ctx>height/4,frame>data[2],

ctx>width*ctx>height/4);

}

else

return 0;//空幀,返回

//執(zhí)行編碼過程

ioctl(x4>dev_fd,S3C_MFC_IOCTL_MFC_H264_ENC_EXE,&x4>enc_exe);

//編碼數(shù)據(jù)輸出

bufsize = x4>enc_exe.out_encoded_size;

memcpy(buf,x4>out_buf,bufsize);

……

return bufsize;

}

X264_close關(guān)閉函數(shù)用于編碼結(jié)束后的資源釋放晌畅,包括取消空間映射和關(guān)閉設(shè)備文件但指。

static av_cold int X264_close(AVCodecContext *avctx){

//取消空間映射

munmap(x4>addr,BUF_SIZE);

//關(guān)閉設(shè)備文件

close(x4>dev_fd);

return 0;

}

解碼函數(shù)的實(shí)現(xiàn)過程類似于編碼函數(shù),包括空間轉(zhuǎn)換抗楔、執(zhí)行解碼和解碼數(shù)據(jù)輸出棋凳。初始化時使用S3C_MFC_IOCTL_MFC_H264_DEC_INIT參數(shù),執(zhí)行時使用S3C_MFC_IOCTL_MFC_H264_ENC_EXE參數(shù)连躏。

4 運(yùn)行測試

s3cx264編解碼器添加到FFmpeg后剩岳,可以通過以下方式測試

① 用如下命令編譯FFmpeg。

./configure enablecrosscompile

arch=armv6 cpu=armv6

targetos=linux crossprefix

=/usr/local/arm/4.3.2/bin/

armlinux

② 運(yùn)行 ./ffmpeg codecs查看可以找到s3cx264編解碼器入热,如圖2所示拍棕。

圖2 FFmpeg顯示s3cx264編解碼器信息

③ 結(jié)合USB攝像頭測試s3cx264編碼。運(yùn)行 ./ffmpeg s 320x240 r 50 f video4linux2 i

/dev/video2 vcodec s3cx264 test.mp4

可以看到FFmpegg正使用s3cx264編碼器將USB攝像頭采集的數(shù)據(jù)編碼壓縮成test.mp4文件勺良。test.mp4能夠正常播放顯示绰播。

以上測試說明已經(jīng)成功地將s3cx264硬件視頻編碼器添加到了FFmpeg中,能夠編碼視頻數(shù)據(jù)尚困,可以運(yùn)用到其他使用FFmpeg庫的多媒體程序中蠢箩。

結(jié)語

對于多媒體開發(fā)來說,編解碼時使用FFmpeg多媒體庫是一個不錯的選擇,支持較多的音視頻編解碼谬泌,編程接口簡單易用示弓。了解FFmpeg編解碼過程,熟悉FFmpeg硬件編解碼器添加方法呵萨,對多媒體開發(fā)奏属,尤其是資源有限的嵌入式多媒體開發(fā)有很大幫助。本文通過分析FFmpeg視頻編解碼過程和三星S3C6410處理器視頻硬件編解碼方法潮峦,在FFmpeg庫中成功添加S3C6410硬件編解碼器囱皿,使FFmpeg庫具有H.264視頻格式的硬件編解碼能力,可運(yùn)用于游戲設(shè)備、監(jiān)控設(shè)備忱嘹、視頻會議設(shè)備和數(shù)字網(wǎng)絡(luò)電視等嵌入式系統(tǒng)中嘱腥,同時也為其他嵌入式設(shè)備添加別的視頻格式的編解碼器到FFmpeg多媒體庫提供了參考。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拘悦,一起剝皮案震驚了整個濱河市齿兔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌础米,老刑警劉巖分苇,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異屁桑,居然都是意外死亡医寿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門蘑斧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來靖秩,“玉大人,你說我怎么就攤上這事竖瘾」低唬” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵捕传,是天一觀的道長惠拭。 經(jīng)常有香客問我,道長乐横,這世上最難降的妖魔是什么求橄? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任今野,我火速辦了婚禮葡公,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘条霜。我一直安慰自己催什,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布宰睡。 她就那樣靜靜地躺著蒲凶,像睡著了一般气筋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上旋圆,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天宠默,我揣著相機(jī)與錄音,去河邊找鬼灵巧。 笑死搀矫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的刻肄。 我是一名探鬼主播瓤球,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼敏弃!你這毒婦竟也來了卦羡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤麦到,失蹤者是張志新(化名)和其女友劉穎绿饵,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瓶颠,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝴罪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了步清。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片要门。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖廓啊,靈堂內(nèi)的尸體忽然破棺而出欢搜,到底是詐尸還是另有隱情,我是刑警寧澤谴轮,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布炒瘟,位于F島的核電站,受9級特大地震影響第步,放射性物質(zhì)發(fā)生泄漏疮装。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一粘都、第九天 我趴在偏房一處隱蔽的房頂上張望廓推。 院中可真熱鬧,春花似錦翩隧、人聲如沸樊展。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽专缠。三九已至雷酪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涝婉,已是汗流浹背哥力。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留墩弯,地道東北人省骂。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像最住,于是被迫代替她去往敵國和親钞澳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,676評論 0 3
  • 說明 FFmpeg是一套開源的音視頻編解碼庫涨缚,有非常強(qiáng)大的功能轧粟,包括視頻采集功能、視頻格式轉(zhuǎn)換等脓魏。眾所周知視頻編解...
    HintLee閱讀 26,519評論 10 10
  • 熟悉命令之后兰吟,自然是對其根據(jù)自己的需求進(jìn)行應(yīng)用了。所以久等的第三編文章就來放放水茂翔。記錄一下在Android端的集成...
    deep_sadness閱讀 1,533評論 0 4
  • 《戴珍珠耳環(huán)的少女》是十七世紀(jì)荷蘭黃金時代繪畫大師約翰內(nèi)斯·維米爾的代表作混蔼,畫中少女,眼神清澈珊燎,嘴唇微啟惭嚣,面露恬靜...
    拾光小世界閱讀 800評論 0 1
  • 五角場特力時尚匯 - 望湘園 菜很辣,連炒飯都是辣的 但悔政,出奇的好吃下飯 已經(jīng)光顧兩次~ 虹口小四川酸菜 酸菜魚并...
    阿囍123閱讀 148評論 1 0