<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          跨平臺播放器開發(fā) (四) 開發(fā)一個播放器需要用到哪些 FFmpeg 知識

          共 13147字,需瀏覽 27分鐘

           ·

          2021-06-28 13:27

          前言

          咱們前面三篇文章主要介紹了如何在各個主流平臺下配置開發(fā)環(huán)境,那么從該篇開始就真正進(jìn)入編碼了。由于該系列定義為「從 0 到 1 「寫一個跨平臺播放器,所以我打算」從淺到深」,從「基礎(chǔ)到進(jìn)階」的路線來進(jìn)行。

          咱們先來看一個流程圖:

          10fc620e1192a1236de765c4aea07990.webp

          該系列文章就是將上圖拆分為具體的代碼模塊,那么該篇咱們主要講解如何利用FFmpeg API 來對一個輸入數(shù)據(jù)進(jìn)行解封裝,讀取原始音頻視頻信息,然后對音頻視頻做一些基本操作?;旧显诓シ牌髂K中用到的FFmpeg API 咱們都要對它有一個了解。

          ?

          ps: 如果對 Mac OS 、Windows 、Linux 下不知道怎么配置 QT & FFmpeg 環(huán)境的可以參考下面文章

          跨平臺播放器開發(fā) (一) QT for MAC OS & FFmpeg 環(huán)境搭建

          跨平臺播放器開發(fā) (二) QT for Linux & FFmpeg 環(huán)境搭建

          跨平臺播放器開發(fā) (三) QT for Windows & FFmpeg 環(huán)境搭建

          ?

          FFmpeg 基礎(chǔ)

          解封裝

          利用 FFmpeg api 來對輸入視頻進(jìn)行解封裝,先來看一下使用 api 的流程

          6c4e8d5b707f6b44b8790bccc75fdd9e.webp

          看完上圖是不是對解封裝的 API 有一個大概的了解? 從一個 輸入 URL到讀取到 「壓縮數(shù)據(jù)流」 就這么幾步,很簡單的,下面我們用代碼實際演示一下:

          1.注冊所有函數(shù)

          av_register_all()

          其實在最新的版本中該函數(shù)已經(jīng)過時了,在最低的版本中還是必須調(diào)用該函數(shù)的。

          b630e61ae869e81be83d8c1fba469f7f.webp

          2.注冊網(wǎng)絡(luò)模塊

          //初始化網(wǎng)絡(luò)庫(可以打開?rtmp、rtsp、http?等協(xié)議的流媒體視頻)?
          avformat_network_init();

          3.打開輸入流并讀取頭信息

          ??//參數(shù)設(shè)置
          ????AVDictionary?*opts?=?
          NULL;
          ????
          //設(shè)置rtsp流tcp協(xié)議打開
          ????av_dict_set(&opts,?
          "rtsp_transport",?"tcp",?0);
          ????
          //網(wǎng)絡(luò)延時時間
          ????av_dict_set(&opts,?
          "max_delay",?"1000",?0);

          ????
          //解封裝上下文
          ????AVFormatContext?*ic?=?
          NULL;
          ????
          int?re?=?avformat_open_input(
          ????????????&ic,
          ????????????inpath,
          ????????????
          0,??//?0表示自動選擇解封器
          ????????????&opts?
          //參數(shù)設(shè)置,比如rtsp的延時時間
          ????);
          ??
          //返回值?0?成功
          ????
          if?(re?!=?0)?{
          ????????
          char?buf[1024]?=?{0};
          ????????av_strerror(re,?buf,?
          sizeof(buf)?-?1);
          ????????
          cout?<<?"open?"?<<?inpath?<<?"?failed!?:"?<<?buf?<<?endl;
          ????????getchar();
          ????????
          return?-1;
          ????}

          這里要注意,調(diào)用該函數(shù)那么在結(jié)尾處一定要調(diào)用 avformat_close_input()

          4.讀取媒體文件數(shù)據(jù)包

          //return?>=0?if?OK,?AVERROR_xxx?on?error?
          re?=?avformat_find_stream_info(ic,?0);

          //打印視頻流詳細(xì)信息
          av_dump_format(ic,?0,?inpath,?0);

          5.獲取音視頻流信息

          1. 通過遍歷的方式獲取
          ????//獲取音視頻流信息?(遍歷,函數(shù)獲?。?/span>
          ????for?(int?i?=?0;?i?<?ic->nb_streams;?i++)?{
          ????????AVStream?*as?=?ic->streams[i];
          ????????cout?<<?"codec_id?=?"?<<?as->codecpar->codec_id?<<?endl;
          ????????cout?<<?"format?=?"?<<?as->codecpar->format?<<?endl;

          ????????//音頻?AVMEDIA_TYPE_AUDIO
          ????????if?(as->codecpar->codec_type?==?AVMEDIA_TYPE_AUDIO)?{
          ????????????audioStream?=?i;
          ????????????cout?<<?i?<<?"音頻信息"?<<?endl;
          ????????????cout?<<?"sample_rate?=?"?<<?as->codecpar->sample_rate?<<?endl;
          ????????????//AVSampleFormat;
          ????????????cout?<<?"channels?=?"?<<?as->codecpar->channels?<<?endl;
          ????????????//一幀數(shù)據(jù)???單通道樣本數(shù)
          ????????????cout?<<?"frame_size?=?"?<<?as->codecpar->frame_size?<<?endl;
          ????????????//1024?*?2?*?2?=?4096??fps?=?sample_rate/frame_size

          ????????}
          ????????????//視頻?AVMEDIA_TYPE_VIDEO
          ????????else?if?(as->codecpar->codec_type?==?AVMEDIA_TYPE_VIDEO)?{
          ????????????videoStream?=?i;
          ????????????cout?<<?i?<<?"視頻信息"?<<?endl;
          ????????????cout?<<?"width="?<<?as->codecpar->width?<<?endl;
          ????????????cout?<<?"height="?<<?as->codecpar->height?<<?endl;
          ????????????//幀率?fps?分?jǐn)?shù)轉(zhuǎn)換
          ????????????cout?<<?"video?fps?=?"?<<?r2d(as->avg_frame_rate)?<<?endl;
          ????????}
          ????}
          1. 通過 API 方式獲取
          //獲取視頻流
          videoStream?=?av_find_best_stream(ic,?AVMEDIA_TYPE_VIDEO,?-1,?-1,?NULL,?0);
          AVStream?*as?=?ic->streams[videoStream];
          cout?<<?i?<<?"視頻信息"?<<?endl;
          cout?<<?"width="?<<?as->codecpar->width?<<?endl;
          cout?<<?"height="?<<?as->codecpar->height?<<?endl;
          //幀率?fps?分?jǐn)?shù)轉(zhuǎn)換
          cout?<<?"video?fps?=?"?<<?r2d(as->avg_frame_rate)?<<?endl;????

          6.讀取壓縮數(shù)據(jù)包

          ????AVPacket?*pkt?=?av_packet_alloc();

          ????for?(;;)?{
          ????????int?re?=?av_read_frame(ic,?pkt);
          ????????if?(re?!=?0)?{
          ????????????//循環(huán)播放
          ????????????cout?<<?"==============================end=============================="?<<?endl;
          ????????????break;
          ????????}
          ????????cout?<<?"pkt->size?=?"?<<?pkt->size?<<?endl;
          ????????//顯示的時間
          ????????cout?<<?"pkt->pts?=?"?<<?pkt->pts?<<?endl;

          ????????//轉(zhuǎn)換為毫秒,方便做同步
          ????????cout?<<?"pkt->pts?ms?=?"?<<?pkt->pts?*?(r2d(ic->streams[pkt->stream_index]->time_base)?*?1000)?<<?endl;

          ????????//解碼時間
          ????????cout?<<?"pkt->dts?=?"?<<?pkt->dts?<<?endl;
          ????????if?(pkt->stream_index?==?videoStream)?{
          ????????????cout?<<?"圖像"?<<?endl;
          ????????}
          ????????if?(pkt->stream_index?==?audioStream)?{
          ????????????cout?<<?"音頻"?<<?endl;
          ????????}
          ????????//釋放,引用計數(shù)-1?為0釋放空間
          ????????av_packet_unref(pkt);
          ????}

          調(diào)試之后的 log

          4fc82fb66b680a507e7b4d599b8e002f.webp

          解碼

          調(diào)用 ffmpeg api 來對音視頻壓縮數(shù)據(jù)解碼的話,其實也很簡單,主要使用如下幾個 api ,見下圖:

          3e810f9592dd8b6bbfd01e8ec4633254.webp

          我們接著在解封裝的代碼基礎(chǔ)上進(jìn)行添加,代碼如下:

          ????//找到視頻解碼器
          ????AVCodec?*vcodec?=?avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);
          ????if?(!vcodec)?{
          ????????cout?<<?"can't?find?the?codec?id"?<<?ic->streams[videoStream]->codecpar->codec_id?<<?endl;
          ????????getchar();
          ????????return?-1;
          ????}
          ????//創(chuàng)建視頻解碼器上下文
          ????AVCodecContext?*vctx?=?avcodec_alloc_context3(vcodec);
          ????//配置解碼器上下文參數(shù)
          ????avcodec_parameters_to_context(vctx,?ic->streams[videoStream]->codecpar);
          ????//配置解碼線程
          ????vctx->thread_count?=?8;
          ????//打開解碼器上下文
          ????re?=?avcodec_open2(vctx,?0,?0);
          ????if?(re?!=?0)?{
          ????????char?buf[1024]?=?{0};
          ????????av_strerror(re,?buf,?sizeof(buf)?-?1);
          ????????cout?<<?"video?avcodec_open2?failed!"?<<?buf?<<?endl;
          ????????getchar();
          ????????return?-1;
          ????}
          ????cout?<<?"video?avcodec_open2?success!"?<<?endl;

          找解碼器也可以通過如下 API 形式進(jìn)行:

          AVCodec?*avcodec_find_decoder_by_name(const?char?*name);

          如果想要打開音頻解碼器,代碼一樣,換下參數(shù)即可,下面進(jìn)行真正解碼:

          ????//malloc?AVPacket并初始化
          ????AVPacket?*pkt?=?av_packet_alloc();
          ????//接收解碼的原始數(shù)據(jù)
          ????AVFrame?*frame?=?av_frame_alloc();
          ????for?(;;)?{
          ????????int?re?=?av_read_frame(ic,?pkt);
          ????????if?(re?!=?0)?{
          ????????????break;
          ????????}

          ????????//解碼視頻
          ????????//發(fā)送?packet?到解碼線程
          ????????re?=?avcodec_send_packet(avcc,?pkt);
          ????????//釋放,引用計數(shù)-1?為0釋放空間
          ????????av_packet_unref(pkt);
          ????
          ????????//一次?send?可能對于多次?receive
          ????????for?(;;)?{
          ????????????re?=?avcodec_receive_frame(avcc,?frame);
          ????????????if?(re?!=?0)break;
          ????????????//釋放,引用計數(shù)-1?為0釋放空間
          ???????????av_frame_unref(frame);
          ????}

          這樣就可以進(jìn)行解碼了,現(xiàn)在我們添加一些打印參數(shù),比如音頻采樣信息,視頻寬高信息:

          87ac53434c13715b13f34c8414fed4f9.webp
          ?

          總時長:totalMs = 10534 ms

          視頻信息:

          bitrate=907_500

          fps = 30.0003

          codec_id = 86018

          format = AV_PIX_FMT_YUV420P 1152

          1080 - 1920

          pict_type= AV_PICTURE_TYPE_I

          音頻信息:

          sample_rate = 48000

          channels = 2

          ?

          視頻像素格式轉(zhuǎn)換

          視頻像素格式其實就是 YUV 轉(zhuǎn) RGB 的一個過程, FFmpeg 也提供了對應(yīng)的 API ,它是使用 CPU 運算能力來轉(zhuǎn)換,效率是比較低的。咱們播放器使用 OpenGL GPU 來轉(zhuǎn),效率比較高。雖然 FFmpeg API 轉(zhuǎn)換效率比較低,但是我們還是可以學(xué)習(xí)一下的。使用流程如下:

          26edae9d8aa4dc41f3f5de1af3410438.webp

          僅僅 2 個 API 就可以達(dá)到對 YUV 的轉(zhuǎn)換或者裁剪,代碼示例:

          ????????????????const?int?in_width?=?frame->width;
          ????????????????const?int?in_height?=?frame->height;
          ????????????????const?int?out_width?=?in_width?/?2;
          ????????????????const?int?out_height?=?in_height?/?2;????????????????

          ???????/**
          ?????????????????*?@param?context???:?縮放上下文,如果為?NULL,那么內(nèi)部會進(jìn)行創(chuàng)建,
          ?????????????????*????????????如果已經(jīng)存在,參數(shù)也沒有發(fā)生變化,那么就直接返回當(dāng)前,否者釋放縮放上下文,重新創(chuàng)建。
          ?????????????????*?@param?srcW??????:?輸入的寬
          ?????????????????*?@param?srcH??????:?輸入的高
          ?????????????????*?@param?srcFormat?:?輸入的格式
          ?????????????????*?@param?dstW????:?輸出的寬
          ?????????????????*?@param?dstH????:?輸出的高
          ?????????????????*?@param?dstFormat?:?輸出的格式
          ?????????????????*?@param?flags???:?提供了一系列的算法,快速線性,差值,矩陣,不同的算法性能也不同,
          ????????????????????????????快速線性算法性能相對較高??倳r長只針對尺寸的變換。
          ?????????????????*?@param?srcFilter?:?輸入過濾器
          ?????????????????*?@param?dstFilter?:?輸出過濾器
          ?????????????????*?@param?param???:?這個跟?flags?算法相關(guān),一般傳入?O
          ?????????????????*?@return??????????:?縮放的上下文
          ?????????????????*/

          ????????????????vsctx?=?sws_getCachedContext(
          ????????????????????????vsctx,//傳入NULL 會新創(chuàng)建
          ????????????????????????in_width,?in_height,?(AVPixelFormat)?frame->format,?//輸入的寬高,格式
          ????????????????????????out_width,?out_height,?AV_PIX_FMT_RGBA,?//輸出的寬高,格式
          ????????????????????????SWS_BILINEAR,?//尺寸變換的算法
          ????????????????????????0,?0,?0
          ????????????????);


          ????????????????????/**
          ?????????????????????*?@param?c?????????縮放上下文
          ?????????????????????*?@param?srcSlice??YUV?切換數(shù)據(jù)可以是指針,也可以是數(shù)組
          ?????????????????????*?@param?srcStride?對應(yīng)?YUV?一行的大小
          ?????????????????????*?@param?srcSliceY?這個用不到傳入?0?即可
          ?????????????????????*?@param?srcSliceH?YUV?的高
          ?????????????????????*?@param?dst???????輸出的像素格式數(shù)據(jù)
          ?????????????????????*?@param?dstStride?輸出的像素格式數(shù)據(jù)的大小
          ?????????????????????*?@return??????????返回轉(zhuǎn)換后的高
          ?????????????????????*/

          ????????????????????re?=?sws_scale(vsctx,
          ???????????????????????????????????frame->data,?//輸入數(shù)據(jù)
          ???????????????????????????????????frame->linesize,//輸入行大小
          ???????????????????????????????????0,
          ???????????????????????????????????frame->height,//輸出高度
          ???????????????????????????????????(uint8_t?*const?*)?(data),?//輸出數(shù)據(jù)
          ???????????????????????????????????lines//輸出大小
          ????????????????????);

          上面的注釋都很詳細(xì),相信大家也能看的明白,最后我們看下調(diào)試后的log,如下:

          ?

          像素格式尺寸轉(zhuǎn)換上下文創(chuàng)建或者獲取成功!

          in_width=1080

          in_height=1920

          out_width=540

          out_height=960

          sws_scale success! return height of the output slice =960 ===============? ?end? ?=================

          ?

          重采樣

          重采樣的意思就是將音頻的輸入?yún)?shù)統(tǒng)一輸出某個特定的值,這樣做的好處就是歸一化播放器的聲音輸出。那么怎么使用 FFmpeg API 來進(jìn)行重采樣呢? 先來看一張流程圖:

          53154047868eefb0fafeaf87de341f07.webp

          我們還是以之前的代碼繼續(xù)寫,

          「我們統(tǒng)一輸出的參數(shù)為 sample_rate=48000,sample_channel=2,sample_fml=AV_SAMPLE_FMT_S16」

          ????...
          ??//音頻重采樣
          ????SwrContext?*asctx?=?swr_alloc();
          ????//設(shè)置重采樣參數(shù)
          ????asctx?=?swr_alloc_set_opts(asctx?//重采樣上下文
          ????????????,?av_get_default_channel_layout(2)//輸出聲道格式
          ????????????,?AV_SAMPLE_FMT_S16?//輸出聲音樣本格式
          ????????????,?48000?//輸出采樣率
          ????????????,?av_get_default_channel_layout(actx->channels)//輸入通道數(shù)
          ????????????,?actx->sample_fmt????????????????????????????//輸入聲音樣本格式
          ????????????,?actx->sample_rate,?0,?0??//輸入音頻采樣率
          ????);
          ????//初始化采樣上下文
          ????re?=?swr_init(asctx);
          ????if?(re?!=?0)?{
          ????????char?buf[1024]?=?{0};
          ????????av_strerror(re,?buf,?sizeof(buf)?-?1);
          ????????cout?<<?"audio?swr_init?failed!"?<<?buf?<<?endl;
          ????????return?-1;
          ????}

          ??...
          ????//重采樣之后存入的數(shù)據(jù)
          ????unsigned?char?*pcm?=?NULL;
          ????for?(;;)?{
          ????????int?re?=?av_read_frame(ic,?pkt);
          ????????if?(re?!=?0)?{
          ????????????//循環(huán)播放
          ????????????cout?<<?"==============================end=============================="?<<?endl;
          //????????????int?ms?=?3000;?//三秒位置?根據(jù)時間基數(shù)(分?jǐn)?shù))轉(zhuǎn)換
          //????????????long?long?pos?=?(double)?ms?/?(double)?1000?*?r2d(ic->streams[pkt->stream_index]->time_base);
          //????????????av_seek_frame(ic,?videoStream,?pos,?AVSEEK_FLAG_BACKWARD?|?AVSEEK_FLAG_FRAME);
          //????????????continue;
          ????????????break;
          ????????}

          ????????cout?<<?"pkt->size?=?"?<<?pkt->size?<<?endl;
          ????????//顯示的時間
          ????????cout?<<?"pkt->pts?=?"?<<?pkt->pts?<<?endl;

          ????????//轉(zhuǎn)換為毫秒,方便做同步
          ????????cout?<<?"pkt->pts?ms?=?"?<<?pkt->pts?*?(r2d(ic->streams[pkt->stream_index]->time_base)?*?1000)?<<?endl;

          ????????//解碼時間
          ????????cout?<<?"pkt->dts?=?"?<<?pkt->dts?<<?endl;
          ????????AVCodecContext?*avcc?=?NULL;
          ????????if?(pkt->stream_index?==?videoStream)?{
          ????????????cout?<<?"圖像"?<<?endl;
          ????????????avcc?=?vctx;
          ????????}
          ????????if?(pkt->stream_index?==?audioStream)?{
          ????????????cout?<<?"音頻"?<<?endl;
          ????????????avcc?=?actx;
          ????????}

          ????????//解碼視頻
          ????????//發(fā)送?packet?到解碼線程
          ????????re?=?avcodec_send_packet(avcc,?pkt);
          ????????//釋放,引用計數(shù)-1?為0釋放空間
          ????????av_packet_unref(pkt);
          ????????if?(re?!=?0)?{
          ????????????char?buf[1024]?=?{0};
          ????????????av_strerror(re,?buf,?sizeof(buf)?-?1);
          ????????????cout?<<?"video?avcodec_send_packet?failed!"?<<?buf?<<?endl;
          ????????????continue;
          ????????}

          ????????//一次?send?可能對于多次?receive
          ????????for?(;;)?{
          ????????????re?=?avcodec_receive_frame(avcc,?frame);
          ????????????if?(re?!=?0)break;
          ?
          ??????????????...
          ????????????????
          ??????????????if?(avcc?==?actx)?{//音頻
          ????????????????uint8_t?*data[2]?=?{0};
          ????????????????if?(!pcm)?pcm?=?new?uint8_t[frame->nb_samples?*?16/8?*?2];
          ????????????????data[0]?=?{pcm};
          ????????????????int?len?=?swr_convert(asctx,?data,?frame->nb_samples?//輸出
          ????????????????????????,?(const?uint8_t?**)?frame->data,?frame->nb_samples?//輸入
          ????????????????);
          ????????????????if?(len?>=?0)?{
          ????????????????????cout?<<?"swr_convert?success?return?len?=?"?<<?len?<<?endl;
          ????????????????}?else?{
          ????????????????????cout?<<?"swr_convert?failed?return?len?=?"?<<?len?<<?endl;
          ????????????????}
          ????????????}
          ????????}
          ??...
          ????}

          ????if?(asctx)swr_close(asctx);
          ????if?(asctx)swr_free(&asctx);????
          ??

          轉(zhuǎn)換后的log:

          ?

          swr_convert success return len = 1024

          ?

          seek 操作

          我們?nèi)绻胍付硞€時間看某段畫面的話就需要對視頻做 seek 操作,F(xiàn)Fmpeg 提供了 「av_seek_frame」 函數(shù)來對視頻的跳轉(zhuǎn),它有 4 個輸入?yún)?shù),含義如下:

          /**
          ?*?根據(jù)時間戳和音頻或視頻的索引?seek?到關(guān)鍵幀的操作
          ?*
          ?*?@param?s?媒體格式上下文
          ?*?@param?stream_index?流索引,傳入?-1?為默認(rèn)
          ?*?@param?timestamp?需要跳轉(zhuǎn)到時間戳的位置
          ?*?@param?flags?seek?的模式
          ?*?@return?>=?0?on?success
          ?*/
          int?av_seek_frame(AVFormatContext?*s,?int?stream_index,?int64_t?timestamp,
          ??????????????????int?flags);

          我們著重看下最后一個 「flags」 參數(shù)

          ?

          //AVSEEK_FLAG_BACKWARD

          seek 到后面的關(guān)鍵幀

          //AVSEEK_FLAG_BYTE

          基于以字節(jié)為單位的位置查找

          //AVSEEK_FLAG_ANY

          Seek 到任意一幀,注意不是關(guān)鍵幀,那么會有花屏的可能。

          //AVSEEK_FLAG_FRAME

          seek 到關(guān)鍵幀的位置

          ?

          我們一般以這樣的形式來進(jìn)行 seek 操作:

          int?ms?=?3000;?//三秒位置?根據(jù)時間基數(shù)(分?jǐn)?shù))轉(zhuǎn)換
          long?long?pos?=?(double)?ms?/?(double)?1000?*?r2d(ic->streams[pkt->stream_index]->time_base);
          av_seek_frame(ic,?videoStream,?pos,?AVSEEK_FLAG_BACKWARD?|?AVSEEK_FLAG_FRAME);

          上面的含義就是定位到 3000 ms 位置后面的關(guān)鍵幀處開始播放。后面播放器 seek 功能我們會介紹如何精準(zhǔn) seek 操作

          該篇文章對于 FFmpeg 的知識我們就介紹到這里,后面在開發(fā)中如果有新遇見的我會再詳細(xì)介紹一下。

          總結(jié)

          播放器要用到的 FFmpeg 知識 大概就這么多,可以發(fā)現(xiàn)這些 API 其實都比較簡單。此刻我相信你已經(jīng)對這些 API 有一定的印象和了解了吧。

          下一篇文章將帶來 QT 如何渲染 PCM 和 YUV 的數(shù)據(jù)。

          「以上代碼可以通過該地址訪問」:https://github.com/yangkun19921001/YKAVStudyPlatform


          瀏覽 48
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天日天天操天天干天天 | 综合久久久福利蜜芽 | 有限公司尻屄视频网站 | 丁香花中文字幕在线播放 | 操人视频网站 |