日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

librtmp源码详解

發布時間:2023/12/31 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 librtmp源码详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  1. librtmp概述

  實時流協議(Real-TimeMessaging Protocol,RTMP)是用于互聯網上傳輸視音頻數據的網絡協議。本API提供了支持RTMP, RTMPT,RTMPE,RTMPS及以上幾種協議的變種(RTMPTE, RTMPTS)協議所需的大部分客戶端功能以及少許的服務器功能。盡管Adobe公司已經公布了RTMP協議規范(RTMP specification),可是本工程并非經過Adobe的協議規范而是經過逆向工程的方式完成的。所以,它的運行方式可能和公布的協議規范有所偏離,可是通常狀況下它和Adobe的客戶端的運行方式是如出一轍的。c++

  本博客將對libRTMP的函數進行簡要說明。 這些函數能夠在 -lrtmp 庫中找到。其余還有不少函數,可是尚未為這些函數寫文檔。git

基本的操做以下文所述:github

RTMP_Alloc() :用于建立一個RTMP的結構體。web

RTMP_Init():初始化RTMP結構體。數組

RTMP_SetupURL():設置推拉流的URL。服務器

RTMP_EnableWrite(): 是否推流。網絡

RTMP_Connect():創建RTMP連接中的網絡鏈接(NetConnection)。app

RTMP_ConnectStream():創建RTMP連接中的網絡流(NetStream)。socket

RTMP_Read():讀取RTMP流的內容。

RTMP_Pause():流播放的時候能夠用于暫停和繼續。

RTMP_Seek():改變流播放的位置。

當RTMP_Read()返回0 字節的時候,表明流已經讀取完畢,然后能夠調用RTMP_Close()。

RTMP_Free():用于釋放RTMP結構體。

全部的數據都使用 FLV 格式進行傳輸。一個基本的會話須要一個RTMP URL。RTMP URL 格式以下所示:

rtmp[t][e|s]://hostname[:port][/app[/playpath]]

  2. librtmp流程圖

  本流程主要為推流示意圖,拉流與此大同小異。

  

?

  3. 源碼剖析

  源碼剖析的建議:

    a. 先了解RTMP協議內容或者結合代碼一塊理解,詳情可查閱:?http://www.cnblogs.com/Kingfans/p/7083100.html;

    b. 先了解AMF編碼機制,詳情課查閱:http://www.cnblogs.com/Kingfans/p/7069542.html;

    c. 發包過程當中請配合wireshark抓包工具一塊理解。

  3.1 RTMP_Alloc

RTMP_Alloc()用于建立一個RTMP的結構體。

/************************************************************************************************************ * @brief 申請RTMP內存 * ************************************************************************************************************/ RTMP* RTMP_Alloc() {return calloc(1, sizeof(RTMP)); }

  3.2 RTMP_Init

RTMP_Init():初始化RTMP結構體。

/************************************************************************************************************ * @brief 初始化RTMP * ************************************************************************************************************/ void RTMP_Init(RTMP *r) { #ifdef CRYPTOif (!RTMP_TLS_ctx)RTMP_TLS_Init(); #endifmemset(r, 0, sizeof(RTMP));r->m_sb.sb_socket = -1;r->m_inChunkSize = RTMP_DEFAULT_CHUNKSIZE;r->m_outChunkSize = RTMP_DEFAULT_CHUNKSIZE;r->m_bSendChunkSizeInfo = 1;r->m_nBufferMS = 30000;r->m_nClientBW = 2500000;r->m_nClientBW2 = 2;r->m_nServerBW = 2500000;r->m_fAudioCodecs = 3191.0;r->m_fVideoCodecs = 252.0;r->Link.timeout = 30;r->Link.swfAge = 30; }

  3.3 RTMP_SetupURL

RTMP_SetupURL():設置推拉流的URL。內部調用了RTMP_ParseURL主要用于解析url,詳見3.3.1。

/************************************************************************************************************ * @brief 設置推流: 地址url; * ************************************************************************************************************/ int RTMP_SetupURL(RTMP *r, char *url) {AVal opt, arg;char *p1, *p2, *ptr = strchr(url, ' ');int ret, len;unsigned int port = 0;if (ptr){*ptr = '\0';}len = (int)strlen(url);// 將url解析后設置到r;ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname, &port, &r->Link.playpath0, &r->Link.app);if (!ret){return ret;}r->Link.port = port;r->Link.playpath = r->Link.playpath0;while (ptr){*ptr++ = '\0';p1 = ptr;p2 = strchr(p1, '=');if (!p2){break;}opt.av_val = p1;opt.av_len = p2 - p1;*p2++ = '\0';arg.av_val = p2;ptr = strchr(p2, ' ');if (ptr){*ptr = '\0';arg.av_len = ptr - p2;/* skip repeated spaces */while (ptr[1] == ' '){*ptr++ = '\0';}}else{arg.av_len = (int)strlen(p2);}/* unescape */port = arg.av_len;for (p1=p2; port >0;){if (*p1 == '\\'){unsigned int c;if (port < 3){return FALSE;}sscanf(p1+1, "%02x", &c);*p2++ = c;port -= 3;p1 += 3;}else{*p2++ = *p1++;port--;}}arg.av_len = p2 - arg.av_val;ret = RTMP_SetOpt(r, &opt, &arg);if (!ret){return ret;}}if (!r->Link.tcUrl.av_len){r->Link.tcUrl.av_val = url;if (r->Link.app.av_len){if (r->Link.app.av_val < url + len){/* if app is part of original url, just use it */r->Link.tcUrl.av_len = r->Link.app.av_len + (r->Link.app.av_val - url);}else{len = r->Link.hostname.av_len + r->Link.app.av_len + sizeof("rtmpte://:65535/");r->Link.tcUrl.av_val = malloc(len);r->Link.tcUrl.av_len = snprintf(r->Link.tcUrl.av_val, len,"%s://%.*s:%d/%.*s",RTMPProtocolStringsLower[r->Link.protocol],r->Link.hostname.av_len, r->Link.hostname.av_val,r->Link.port,r->Link.app.av_len, r->Link.app.av_val);r->Link.lFlags |= RTMP_LF_FTCU;}}else{r->Link.tcUrl.av_len = (int)strlen(url);}}#ifdef CRYPTOif ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len)RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize,(unsigned char *)r->Link.SWFHash, r->Link.swfAge); #endifSocksSetup(r, &r->Link.sockshost);if (r->Link.port == 0){if (r->Link.protocol & RTMP_FEATURE_SSL){r->Link.port = 443;}else if (r->Link.protocol & RTMP_FEATURE_HTTP){r->Link.port = 80;}else{r->Link.port = 1935;}}return TRUE; }

  3.3.1 RTMP_ParseURL

RTMP_ParseURL用于解析url,就是將url字符串內的協議類型、主機名稱、端口號、appname、playpath解析出來。

int RTMP_ParseURL(const char *url, int *protocol, AVal* host, unsigned int *port,AVal* playpath, AVal* app) {char *p, *end, *col, *ques, *slash;RTMP_Log(RTMP_LOGDEBUG, "RTMP_ParseURL");*protocol = RTMP_PROTOCOL_RTMP;*port = 0;playpath->av_len = 0;playpath->av_val = NULL;app->av_len = 0;app->av_val = NULL;/* Old School Parsing *//* look for usual :// pattern */p = strstr(url, "://");if(!p){RTMP_Log(RTMP_LOGERROR, "RTMP URL: No :// in url!");return FALSE;}{int len = (int)(p-url);if (len == 4 && strncasecmp(url, "rtmp", 4) == 0){*protocol = RTMP_PROTOCOL_RTMP;}else if (len == 5 && strncasecmp(url, "rtmpt", 5) == 0){*protocol = RTMP_PROTOCOL_RTMPT;}else if (len == 5 && strncasecmp(url, "rtmps", 5) == 0){*protocol = RTMP_PROTOCOL_RTMPS;}else if (len == 5 && strncasecmp(url, "rtmpe", 5) == 0){*protocol = RTMP_PROTOCOL_RTMPE;}else if (len == 5 && strncasecmp(url, "rtmfp", 5) == 0){*protocol = RTMP_PROTOCOL_RTMFP;}else if (len == 6 && strncasecmp(url, "rtmpte", 6) == 0){*protocol = RTMP_PROTOCOL_RTMPTE;}else if (len == 6 && strncasecmp(url, "rtmpts", 6) == 0){*protocol = RTMP_PROTOCOL_RTMPTS;}else{RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n");goto parsehost;}}RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol);parsehost:/* let's get the hostname */p+=3;/* check for sudden death */if(*p==0){RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!");return FALSE;}end = p + strlen(p);col = strchr(p, ':');ques = strchr(p, '?');slash = strchr(p, '/');{int hostlen;if (slash){hostlen = slash - p;}else{hostlen = end - p;}if (col && col - p < hostlen){hostlen = col - p;}if(hostlen < 256){host->av_val = p;host->av_len = hostlen;RTMP_Log(RTMP_LOGDEBUG, "Parsed host : %.*s", hostlen, host->av_val);}else{RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!");}p+=hostlen;}/* get the port number if available */if(*p == ':'){unsigned int p2;p++;p2 = atoi(p);if(p2 > 65535){RTMP_Log(RTMP_LOGWARNING, "Invalid port number!");}else{*port = p2;}}if(!slash){RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!");return TRUE;}p = slash+1;{/* parse application** rtmp://host[:port]/app[/appinstance][/...]* application = app[/appinstance]*/char *slash2, *slash3 = NULL, *slash4 = NULL;int applen, appnamelen;slash2 = strchr(p, '/');if (slash2){slash3 = strchr(slash2+1, '/');}if (slash3){slash4 = strchr(slash3+1, '/');}applen = end-p; /* ondemand, pass all parameters as app */appnamelen = applen; /* ondemand length */if(ques && strstr(p, "slist=")) /* whatever it is, the '?' and slist= means we need to use everything as app and parse plapath from slist= */{appnamelen = ques-p;}else if(strncmp(p, "ondemand/", 9)==0){/* app = ondemand/foobar, only pass app=ondemand */applen = 8;appnamelen = 8;}else /* app!=ondemand, so app is app[/appinstance] */{if (slash4){appnamelen = slash4-p;}else if (slash3){appnamelen = slash3-p;}else if (slash2){appnamelen = slash2-p;}applen = appnamelen;}app->av_val = p;app->av_len = applen;RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p);p += appnamelen;}if (*p == '/'){p++;}if (end-p){AVal av = {p, end-p};RTMP_ParsePlaypath(&av, playpath);}return TRUE; }

  3.4 RTMP_EnableWrite

RTMP_EnableWrite()設置為推流狀態。

/************************************************************************************************************ * @brief 是否進行推流; * ************************************************************************************************************/ void RTMP_EnableWrite(RTMP *r) {r->Link.protocol |= RTMP_FEATURE_WRITE; }

  3.5 RTMP_Connect

RTMP_Connect():創建RTMP連接中的網絡鏈接(NetConnection)。主要分為RTMP_Connect0(3.5.1)+ RTMP_Connect1(3.5.2)。

/************************************************************************************************************ * @brief 創建RTMP中的NetConnection * * @return 成功返回TRUE, 不然返回FALSE. ************************************************************************************************************/ int RTMP_Connect(RTMP *r, RTMPPacket *cp) {// Socket結構體;struct sockaddr_storage service;if (!r->Link.hostname.av_len){return FALSE;}// COMODO security software sandbox blocks all DNS by returning "host not found"HOSTENT *h = gethostbyname("localhost");if (!h && GetLastError() == WSAHOST_NOT_FOUND){RTMP_Log(RTMP_LOGERROR, "RTMP_Connect: Connection test failed. This error is likely caused by Comodo Internet Security running OBS in sandbox mode. Please add OBS to the Comodo automatic sandbox exclusion list, restart OBS and try again (11001).");return FALSE;}memset(&service, 0, sizeof(service));if (r->Link.socksport){// 加入地址信息, 使用SOCKS鏈接;if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport)){return FALSE;}}else{// 直接鏈接;if (!add_addr_info(&service, &r->Link.hostname, r->Link.port)){return FALSE;}}RTMP_Log(RTMP_LOGDEBUG, "%s, 創建鏈接:第0次鏈接。開始創建Socket鏈接", __FUNCTION__);// RTMP_Connect0()主要用于創建Socket鏈接,并未開始真正的創建RTMP鏈接;if (!RTMP_Connect0(r, (struct sockaddr *)&service)){RTMP_Log(RTMP_LOGDEBUG, "%s, 創建鏈接:第0次鏈接。創建Socket鏈接失敗", __FUNCTION__);return FALSE;}RTMP_Log(RTMP_LOGDEBUG, "%s, 創建鏈接:第0次鏈接。創建Socket鏈接成功", __FUNCTION__);r->m_bSendCounter = TRUE;// 真正創建RTMP鏈接的函數;return RTMP_Connect1(r, cp); }

  3.5.1 RTMP_Connect0

RTMP_Connect0():第0次鏈接,創建socket鏈接。

/************************************************************************************************************ * @brief 第0次鏈接,創建Socket鏈接 * * @return 成功返回TRUE, 不然返回FALSE. ************************************************************************************************************/ int RTMP_Connect0(RTMP *r, struct sockaddr * service) {int on = 1;r->m_sb.sb_timedout = FALSE;r->m_pausing = 0;r->m_fDuration = 0.0;// 建立一個Socket,并把Socket序號賦值給相應變量;//r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);r->m_sb.sb_socket = WSASocket(service->sa_family, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);if (r->m_sb.sb_socket != -1){if(r->m_bindIP.addrLen){if (bind(r->m_sb.sb_socket, (const struct sockaddr *)&r->m_bindIP.addr, r->m_bindIP.addrLen) < 0){int err = GetSockError();RTMP_Log(RTMP_LOGERROR, "%s, failed to bind socket: %s (%d)",__FUNCTION__, socketerror(err), err);RTMP_Close(r);return FALSE;}}// 定義函數int connect (int sockfd, struct sockaddr* serv_addr, int addrlen);    // 函數說明connect()用來將參數sockfd 的Socket連至參數serv_addr指定的網絡地址。參數addrlen為sockaddr的結構長度。 // 鏈接; if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr_storage)) < 0){int err = GetSockError();switch (err){case 10061:{RTMP_Log(RTMP_LOGERROR, "%s is offline. Try a different server (10061).", r->Link.hostname.av_val);}break;case 10013:{RTMP_Log(RTMP_LOGERROR, "The connection is being blocked by a firewall or other security software (10013).");}break;case 10060:{RTMP_Log(RTMP_LOGERROR, "The connection timed out. Try a different server, or check that the connection is not being blocked by a firewall or other security software (10060).");}break;default:{RTMP_Log(RTMP_LOGERROR, "%s, failed to connect socket: %s (%d)", __FUNCTION__, socketerror(err), err);}break;}RTMP_Close(r);return FALSE;}// 指定了端口號 (注:這不是必需的);if (r->Link.socksport){RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);// 談判? 發送數據報以進行談判? ;if (!SocksNegotiate(r)){RTMP_Log(RTMP_LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__);RTMP_Close(r);return FALSE;}}}else{RTMP_Log(RTMP_LOGERROR, "%s, failed to create socket. Error: %d", __FUNCTION__,GetSockError());return FALSE;}/* set timeout */// 超時;{SET_RCVTIMEO(tv, r->Link.timeout);if (setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv))){RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!", __FUNCTION__, r->Link.timeout);}}if (!r->m_bUseNagle){setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&on, sizeof(on));}return TRUE; }

  3.5.2 RTMP_Connect1

RTMP_Connect1():第1次鏈接,創建真正的rtmp鏈接。主要分為HandShake握手(3.5.2.1)、SendConnectPacket發送命令請求(3.5.2.2)。

/************************************************************************************************************ * @brief 第1次鏈接,創建RTMP鏈接 * ************************************************************************************************************/ int RTMP_Connect1(RTMP *r, RTMPPacket *cp) {if (r->Link.protocol & RTMP_FEATURE_SSL){ #if defined(CRYPTO) && !defined(NO_SSL)TLS_client(RTMP_TLS_ctx, r->m_sb.sb_ssl);TLS_setfd(r->m_sb.sb_ssl, r->m_sb.sb_socket);if (TLS_connect(r->m_sb.sb_ssl) < 0){RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);RTMP_Close(r);return FALSE;} #elseRTMP_Log(RTMP_LOGERROR, "%s, no SSL/TLS support", __FUNCTION__);RTMP_Close(r);return FALSE;#endif}// 使用HTTP;if (r->Link.protocol & RTMP_FEATURE_HTTP){r->m_msgCounter = 1;r->m_clientID.av_val = NULL;r->m_clientID.av_len = 0;HTTP_Post(r, RTMPT_OPEN, "", 1);if (HTTP_read(r, 1) != 0){r->m_msgCounter = 0;RTMP_Log(RTMP_LOGDEBUG, "%s, Could not connect for handshake", __FUNCTION__);RTMP_Close(r);return 0;}r->m_msgCounter = 0;}RTMP_Log(RTMP_LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__);// 握手(C0+C1, S0+S1+S2, C1);if (!HandShake(r, TRUE)){RTMP_Log(RTMP_LOGERROR, "%s, handshake failed.", __FUNCTION__);RTMP_Close(r);return FALSE;}RTMP_Log(RTMP_LOGDEBUG, "%s, handshaked", __FUNCTION__);if (!SendConnectPacket(r, cp)){RTMP_Log(RTMP_LOGERROR, "%s, RTMP connect failed.", __FUNCTION__);RTMP_Close(r);return FALSE;} return TRUE; }

  3.5.2.1 HandShake

HandShake():握手過程實現(C0+C1, S0+S1+S2, C2), 具體查看RTMP協議規范。

/************************************************************************************************************ * @brief 客戶端握手過程; * * C0和C1放在一個buffer中發送出去,當客戶端收齊S0和S1數據后,開始發送C2; * 當客戶端收到S2后并驗證,則客戶端的握手完成; * 此處將就收到的S1原封不動的當成C2發送給服務器端; * * C0/S0 (1個字節) : 表示版本號; * C1/S1 (1536字節) : 格式為 | time(4字節) | 0 0 0 0 (4字節) | 1528個隨機數 | * C2/S2 (1536字節) : 格式為 | time(4字節)(對等端發送的時間) | time2 (4字節) | 1528個對等端隨機回復 | * * @return 握手成功返回TRUE, 不然返回FALSE. ************************************************************************************************************/ static int HandShake(RTMP *r, int FP9HandShake) {int i = 0;uint32_t uptime = 0, suptime = 0; // 客戶端和服務器端時間;int bMatch = 0;char type;char strC[RTMP_SIG_SIZE + 1]; // C0+C1;char* strC1 = strC + 1; // C1;char strC2[RTMP_SIG_SIZE]; // C2;char strS2[RTMP_SIG_SIZE]; // S2// RTMP協議版本號為0x03, 即C0數據;strC[0] = 0x03; // not encrypted: 沒有加密;// 獲取系統時間(毫秒為單位),將其寫入到C1中,占4個字節;uptime = htonl(RTMP_GetTime());memcpy(strC1, &uptime, 4);// 上次對方返回請求的時間(毫秒為單位),將其寫入到C1中;memset(&strC1[4], 0, 4);#ifdef _DEBUG// debug版,后面的1528個隨機數簡單的都設為0xff;for (i = 8; i < RTMP_SIG_SIZE; i++){strC1[i] = 0xff;} #else// release版,使用rand()循環生成1528個偽隨機數;for (i = 8; i < RTMP_SIG_SIZE; i++){strC1[i] = (char)(rand() % 256);} #endif// 發送握手數據C0和C1 if (!WriteN(r, strC, RTMP_SIG_SIZE + 1)){return FALSE;}// 讀取數據報,長度為1,存入type中;// 此處讀取的是服務器端發送來的S0,表示服務器使用的Rtmp版本;if (ReadN(r, &type, 1) != 1){/* 0x03 or 0x06 (03是明文,06是加密,其余值非法)*/return FALSE;}RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);// 客戶端要求的版本與服務器端提供的版本不同;if (type != strC[0]){RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d", __FUNCTION__, strC[0], type);}// 讀取服務器端發送過來的S1數據賦值給C2,并判斷隨機序列長度是否相同;if (ReadN(r, strC2, RTMP_SIG_SIZE) != RTMP_SIG_SIZE){return FALSE;}/* decode server response */// 把serversig的前4個字節賦值給suptime;// S1中的time與C2中的time應該相同;memcpy(&suptime, strC2, 4);// 將網絡字節序轉化為主機字節序,即大端轉小端;suptime = ntohl(suptime);RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, strC2[4], strC2[5], strC2[6], strC2[7]);/* 2nd part of handshake */// 發送握手數據C2(1536個字節)給服務器;if (!WriteN(r, strC2, RTMP_SIG_SIZE)){return FALSE;}// 讀取從服務器發送過來的握手數據S2(1536個字節);if (ReadN(r, strS2, RTMP_SIG_SIZE) != RTMP_SIG_SIZE){return FALSE;}// 比較客戶端C1和服務器端S2的1536個數是否匹配;bMatch = (memcmp(strS2, strC1, RTMP_SIG_SIZE) == 0);if (!bMatch){RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);}return TRUE; }

wireshark抓包結果:

  3.5.2.2 SendConnectPacket

SendConnectPacket()發送命令請求:? set chunk size 和 connect(stream id)。

/************************************************************************************************************ * @brief 發送connect命令; * 這是每次程序運行的時候發送的第一個命令消息; * 命令消息由命令名,傳輸ID,和命令對象組成; * 命令對象由一系列的相關參數組成; * 可參考rtmp協議:rtmp命令消息--4.1.1節; * * set chunk size + connect(stream id) ************************************************************************************************************/ static int SendConnectPacket(RTMP *r, RTMPPacket *cp) {RTMPPacket packet;char pbuf[4096], *pend = pbuf + sizeof(pbuf);char *enc;if (cp){return RTMP_SendPacket(r, cp, TRUE);}if((r->Link.protocol & RTMP_FEATURE_WRITE) && r->m_bSendChunkSizeInfo){packet.m_nChannel = 0x02;packet.m_headerType = RTMP_PACKET_SIZE_LARGE;packet.m_packetType = RTMP_PACKET_TYPE_CHUNK_SIZE;packet.m_nTimeStamp = 0;packet.m_nInfoField2 = 0;packet.m_hasAbsTimestamp = 0;packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;packet.m_nBodySize = 4;enc = packet.m_body;AMF_EncodeInt32(enc, pend, r->m_outChunkSize);// 發送 set chunk size;if (!RTMP_SendPacket(r, &packet, FALSE)){return 0;}}packet.m_nChannel = 0x03; /* control channel (invoke) */packet.m_headerType = RTMP_PACKET_SIZE_LARGE;packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;packet.m_nTimeStamp = 0;packet.m_nInfoField2 = 0;packet.m_hasAbsTimestamp = 0;packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;enc = packet.m_body;enc = AMF_EncodeString(enc, pend, &av_connect);enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);*enc++ = AMF_OBJECT;enc = AMF_EncodeNamedString(enc, pend, &av_app, &r->Link.app);if (!enc){return FALSE;}if (r->Link.protocol & RTMP_FEATURE_WRITE){enc = AMF_EncodeNamedString(enc, pend, &av_type, &av_nonprivate);if (!enc){return FALSE;}}if (r->Link.flashVer.av_len){enc = AMF_EncodeNamedString(enc, pend, &av_flashVer, &r->Link.flashVer);if (!enc){return FALSE;}}if (r->Link.swfUrl.av_len){enc = AMF_EncodeNamedString(enc, pend, &av_swfUrl, &r->Link.swfUrl);if (!enc){return FALSE;}}if (r->Link.tcUrl.av_len){enc = AMF_EncodeNamedString(enc, pend, &av_tcUrl, &r->Link.tcUrl);if (!enc){return FALSE;}}if (!(r->Link.protocol & RTMP_FEATURE_WRITE)){enc = AMF_EncodeNamedBoolean(enc, pend, &av_fpad, FALSE);if (!enc){return FALSE;}enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 15.0);if (!enc){return FALSE;}enc = AMF_EncodeNamedNumber(enc, pend, &av_audioCodecs, r->m_fAudioCodecs);if (!enc){return FALSE;}enc = AMF_EncodeNamedNumber(enc, pend, &av_videoCodecs, r->m_fVideoCodecs);if (!enc){return FALSE;}enc = AMF_EncodeNamedNumber(enc, pend, &av_videoFunction, 1.0);if (!enc){return FALSE;}if (r->Link.pageUrl.av_len){enc = AMF_EncodeNamedString(enc, pend, &av_pageUrl, &r->Link.pageUrl);if (!enc){return FALSE;}}}if (r->m_fEncoding != 0.0 || r->m_bSendEncoding){/* AMF0, AMF3 not fully supported yet */enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, r->m_fEncoding);if (!enc){return FALSE;}}if (enc + 3 >= pend){return FALSE;}*enc++ = 0;*enc++ = 0; /* end of object - 0x00 0x00 0x09 */*enc++ = AMF_OBJECT_END;/* add auth string */if (r->Link.auth.av_len){enc = AMF_EncodeBoolean(enc, pend, r->Link.lFlags & RTMP_LF_AUTH);if (!enc){return FALSE;}enc = AMF_EncodeString(enc, pend, &r->Link.auth);if (!enc){return FALSE;}}if (r->Link.extras.o_num){int i;for (i = 0; i < r->Link.extras.o_num; i++){enc = AMFProp_Encode(&r->Link.extras.o_props[i], enc, pend);if (!enc){return FALSE;}}}packet.m_nBodySize = enc - packet.m_body;// 發送 connect(streamid);return RTMP_SendPacket(r, &packet, TRUE); }

wireshark抓包結果:

  3.6 RTMP_ConnectStream

RTMP_ConnectStream(): 創建RTMP中的NetStream。此處while循環接收消息并調用RTMP_ClientPacket進行處理。

/************************************************************************************************************ * @brief 創建RTMP中的NetStream * * @return 成功返回TRUE, 不然返回FALSE. ************************************************************************************************************/ int RTMP_ConnectStream(RTMP *r, int seekTime) {RTMPPacket packet = { 0 };/* seekTime was already set by SetupStream / SetupURL.* This is only needed by ReconnectStream.*/if (seekTime > 0){r->Link.seekTime = seekTime;}r->m_mediaChannel = 0;while (!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet)){if (RTMPPacket_IsReady(&packet)){if (!packet.m_nBodySize){continue;}if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||(packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||(packet.m_packetType == RTMP_PACKET_TYPE_INFO)){RTMP_Log(RTMP_LOGWARNING, "Received FLV packet before play()! Ignoring.");RTMPPacket_Free(&packet);continue;}RTMP_ClientPacket(r, &packet);RTMPPacket_Free(&packet);}}return r->m_bPlaying; }

  3.6.1 RTMP_ClientPacket

RTMP_ClientPacket():? 處理收到的消息。

/************************************************************************************************************ * @brief 處理接收到的Chunk; * * @return 有數據返回TRUE, 無返回FALSE. ************************************************************************************************************/ int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet) {int bHasMediaPacket = 0;switch (packet->m_packetType){// RTMP消息類型ID=1 設置塊大小;case RTMP_PACKET_TYPE_CHUNK_SIZE:{/* chunk size */RTMP_Log(RTMP_LOGDEBUG, "處理消息: chunk_size (m_packetType=1)\n");HandleChangeChunkSize(r, packet);}break;// RTMP消息類型ID=3 致謝;case RTMP_PACKET_TYPE_BYTES_READ_REPORT:{/* bytes read report */RTMP_Log(RTMP_LOGDEBUG, "處理消息: bytes_read_report (m_packetType=3)\n ");}break;// RTMP消息類型ID=4 用戶控制;case RTMP_PACKET_TYPE_CONTROL:{/* ctrl */RTMP_Log(RTMP_LOGDEBUG, "處理消息: control (m_packetType=4)\n ");HandleCtrl(r, packet);}break;// RTMP消息類型ID=5 ;case RTMP_PACKET_TYPE_SERVER_BW:{/* server bw */RTMP_Log(RTMP_LOGDEBUG, "處理消息: server_bw (m_packetType=5)\n ");HandleServerBW(r, packet);}break;// RTMP消息類型ID=6;case RTMP_PACKET_TYPE_CLIENT_BW:{/* client bw */RTMP_Log(RTMP_LOGDEBUG, "處理消息: client_bw (m_packetType=6)\n ");HandleClientBW(r, packet);}break;// RTMP消息類型ID=8 音頻數據;case RTMP_PACKET_TYPE_AUDIO:{/* audio data */RTMP_Log(RTMP_LOGDEBUG, "處理消息: audio (m_packetType=8)\n ");HandleAudio(r, packet);bHasMediaPacket = 1;if (!r->m_mediaChannel){r->m_mediaChannel = packet->m_nChannel;}if (!r->m_pausing){r->m_mediaStamp = packet->m_nTimeStamp;}}break;// RTMP消息類型ID=9 視頻數據;case RTMP_PACKET_TYPE_VIDEO:{/* video data */RTMP_Log(RTMP_LOGDEBUG, "處理消息: video (m_packetType=9)\n ");HandleVideo(r, packet);bHasMediaPacket = 1;if (!r->m_mediaChannel){r->m_mediaChannel = packet->m_nChannel;}if (!r->m_pausing){r->m_mediaStamp = packet->m_nTimeStamp;}}break;// RTMP消息類型ID=15 AMF3編碼 忽略; case RTMP_PACKET_TYPE_FLEX_STREAM_SEND:{/* flex stream send */RTMP_Log(RTMP_LOGDEBUG, "%s, flex stream send, size %u bytes, not supported, ignoring", __FUNCTION__, packet->m_nBodySize);}break;// RTMP消息類型ID=16 AMF3編碼 忽略;case RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT:{/* flex shared object */RTMP_Log(RTMP_LOGDEBUG, "%s, flex shared object, size %u bytes, not supported, ignoring", __FUNCTION__, packet->m_nBodySize);}break;// RTMP消息類型ID=17 AMF3編碼 忽略 case RTMP_PACKET_TYPE_FLEX_MESSAGE:{/* flex message */RTMP_Log(RTMP_LOGDEBUG,"%s, flex message, size %u bytes, not fully supported",__FUNCTION__, packet->m_nBodySize);/*RTMP_LogHex(packet.m_body, packet.m_nBodySize); *//* some DEBUG code */#if 0RTMP_LIB_AMFObject obj;int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);if(nRes < 0){RTMP_Log(RTMP_LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);/*return; */}obj.Dump();#endifif (HandleInvoke(r, packet->m_body + 1, packet->m_nBodySize - 1) == 1){bHasMediaPacket = 2;}}break;// RTMP消息類型ID=18 AMF0編碼 數據消息;case RTMP_PACKET_TYPE_INFO:{/* metadata (notify) */RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__, packet->m_nBodySize);// 處理元數據;if (HandleMetadata(r, packet->m_body, packet->m_nBodySize)){bHasMediaPacket = 1;}}break;// RTMP消息類型ID=19 AMF0編碼,忽略;case RTMP_PACKET_TYPE_SHARED_OBJECT:{RTMP_Log(RTMP_LOGDEBUG, "%s, shared object, not supported, ignoring", __FUNCTION__);}break;// RTMP消息類型ID=20 AMF0編碼,命令消息 case RTMP_PACKET_TYPE_INVOKE:{/* invoke */RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__, packet->m_nBodySize);/*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1){bHasMediaPacket = 2;}}break;// RTMP消息類型ID=22case RTMP_PACKET_TYPE_FLASH_VIDEO:{/* go through FLV packets and handle metadata packets */unsigned int pos = 0;uint32_t nTimeStamp = packet->m_nTimeStamp;while (pos + 11 < packet->m_nBodySize){uint32_t dataSize = AMF_DecodeInt24(packet->m_body + pos + 1); /* size without header (11) and prevTagSize (4) */if (pos + 11 + dataSize + 4 > packet->m_nBodySize){RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!");break;}if (packet->m_body[pos] == 0x12){HandleMetadata(r, packet->m_body + pos + 11, dataSize);}else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9){nTimeStamp = AMF_DecodeInt24(packet->m_body + pos + 4);nTimeStamp |= (packet->m_body[pos + 7] << 24);}pos += (11 + dataSize + 4);}if (!r->m_pausing)r->m_mediaStamp = nTimeStamp;/* FLV tag(s) *//*RTMP_Log(RTMP_LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize); */bHasMediaPacket = 1;}break;default:{RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,packet->m_packetType); #ifdef _DEBUGRTMP_LogHex(RTMP_LOGDEBUG, packet->m_body, packet->m_nBodySize); #endif}break;}return bHasMediaPacket; }

wireshark抓包結果:

  3.7 RTMP_SendPacket

RTMP_SendPacket():? 消息流發送,內含分塊處理,具體可結合RTMP協議規范。

/************************************************************************************************************ * @brief 消息流發送: 包括分塊發送實現; * ************************************************************************************************************/ int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue) {const RTMPPacket *prevPacket;uint32_t last = 0;int nSize;int hSize, cSize;char *header, *hptr, *hend, hbuf[RTMP_MAX_HEADER_SIZE], c;uint32_t t;char *buffer, *tbuf = NULL, *toff = NULL;int nChunkSize;int tlen;if (packet->m_nChannel >= r->m_channelsAllocatedOut){int n = packet->m_nChannel + 10;RTMPPacket **packets = realloc(r->m_vecChannelsOut, sizeof(RTMPPacket*) * n);if (!packets){free(r->m_vecChannelsOut);r->m_vecChannelsOut = NULL;r->m_channelsAllocatedOut = 0;return FALSE;}r->m_vecChannelsOut = packets;memset(r->m_vecChannelsOut + r->m_channelsAllocatedOut, 0, sizeof(RTMPPacket*) * (n - r->m_channelsAllocatedOut));r->m_channelsAllocatedOut = n;}// 前一個packet存在且不是完整的ChunkMsgHeader,所以有可能須要調整塊消息頭的類型;// fmt字節;// case 0: chunk msg header 長度為11;// case 1: chunk msg header 長度為7;// case 2: chunk msg header 長度為3;// case 3: chunk msg header 長度為0;prevPacket = r->m_vecChannelsOut[packet->m_nChannel];if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE){/* compress a bit by using the prev packet's attributes */// 獲取ChunkMsgHeader類型,前一個Chunk與當前Chunk比較;if (prevPacket->m_nBodySize == packet->m_nBodySize&& prevPacket->m_packetType == packet->m_packetType&& packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM){// 若是先后兩個塊的大小、包類型都相同,則將塊頭類型fmt設為2; // 便可省略消息長度、消息類型id、消息流id; // 能夠參考官方協議:流的分塊 --- 6.1.2.3節;packet->m_headerType = RTMP_PACKET_SIZE_SMALL;}if (prevPacket->m_nTimeStamp == packet->m_nTimeStamp&& packet->m_headerType == RTMP_PACKET_SIZE_SMALL){// 先后兩個塊的時間戳相同,且塊頭類型fmt為2,則相應的時間戳也可省略,所以將塊頭類型置為3;// 能夠參考官方協議:流的分塊 --- 6.1.2.4節; packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;}last = prevPacket->m_nTimeStamp;}// 塊頭類型fmt取值0、一、二、3; 超過3就表示出錯(fmt占二個字節);if (packet->m_headerType > 3) /* sanity */{RTMP_Log(RTMP_LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.", (unsigned char)packet->m_headerType);return FALSE;}// 塊頭初始大小 = 基本頭(1字節) + 塊消息頭大小(11/7/3/0) = [12, 8, 4, 1]; // 塊基本頭是1-3字節,所以用變量cSize來表示剩下的0-2字節;// nSize 表示塊頭初始大小, hSize表示塊頭大小; nSize = packetSize[packet->m_headerType];hSize = nSize;cSize = 0;t = packet->m_nTimeStamp - last; // 時間戳增量;if (packet->m_body){// m_body是指向負載數據首地址的指針; "-"號用于指針前移;// header塊頭的首指針; hend塊頭的尾指針;header = packet->m_body - nSize;hend = packet->m_body;}else{header = hbuf + 6;hend = hbuf + sizeof(hbuf);}if (packet->m_nChannel > 319){// 塊流id(cs id)大于319,則塊基本頭占3個字節;cSize = 2;}else if (packet->m_nChannel > 63){// 塊流id(cs id)在64與319之間,則塊基本頭占2個字節;cSize = 1;}// ChunkBasicHeader的長度比初始長度還要長;if (cSize){// header指向塊頭;header -= cSize;// hSize加上ChunkBasicHeader的長度(比初始長度多出來的長度); hSize += cSize;}// nSize>1表示塊消息頭至少有3個字節,即存在timestamp字段;// 相對TimeStamp大于0xffffff,此時須要使用ExtendTimeStamp;if (nSize > 1 && t >= 0xffffff){header -= 4;hSize += 4;}hptr = header;// 把ChunkBasicHeader的Fmt類型左移6位;c = packet->m_headerType << 6;// 設置basic header的第一個字節值,前兩位為fmt;// 能夠參考官方協議:流的分塊 --- 6.1.1節;switch (cSize){case 0:{// 把ChunkBasicHeader的低6位設置成ChunkStreamID( cs id ) c |= packet->m_nChannel;}break;case 1:{// 同理 但低6位設置成000000;}break;case 2:{// 同理 但低6位設置成000001;c |= 1;}break;}// 能夠拆分紅兩句*hptr=c; hptr++;// 此時hptr指向第2個字節;*hptr++ = c;// 設置basic header的第二(三)個字節值;if (cSize){// 將要放到第2字節的內容tmp;int tmp = packet->m_nChannel - 64;// 獲取低位存儲與第2字節;*hptr++ = tmp & 0xff;if (cSize == 2){// ChunkBasicHeader是最大的3字節時,獲取高位存儲于最后1個字節(注意:排序使用大端序列,和主機相反);*hptr++ = tmp >> 8;}}// ChunkMsgHeader長度為十一、七、3 都含有timestamp(3字節);if (nSize > 1){// 將時間戳(相對或絕對)轉化為3個字節存入hptr 若是時間戳超過0xffffff 則后面還要填入Extend Timestamp;hptr = AMF_EncodeInt24(hptr, hend, t > 0xffffff ? 0xffffff : t);}// ChunkMsgHeader長度為十一、7,都含有 msg length + msg type id;if (nSize > 4){// 將消息長度(msg length)轉化為3個字節存入hptr;hptr = AMF_EncodeInt24(hptr, hend, packet->m_nBodySize);*hptr++ = packet->m_packetType;}// ChunkMsgHeader長度為11 含有msg stream id(小端);if (nSize > 8){hptr += EncodeInt32LE(hptr, packet->m_nInfoField2);}if (nSize > 1 && t >= 0xffffff){hptr = AMF_EncodeInt32(hptr, hend, t);}// 到此為止 已經將塊頭填寫好了; // 此時nSize表示負載數據的長度 buffer是指向負載數據區的指針;nSize = packet->m_nBodySize;buffer = packet->m_body;nChunkSize = r->m_outChunkSize; //Chunk大小 默認是128字節;RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket, nSize);/* send all chunks in one HTTP request 使用HTTP協議 */if (r->Link.protocol & RTMP_FEATURE_HTTP){// nSize: Message負載長度; nChunkSize:Chunk長度; // 例nSize: 307 nChunkSize: 128 ; // 可分為(307 + 128 - 1)/128 = 3個;// 為何加 nChunkSize - 1? 由于除法會只取整數部分!;int chunks = (nSize+nChunkSize-1) / nChunkSize;// Chunk個數超過一個;if (chunks > 1){ // 注意: ChunkBasicHeader的長度 = cSize + 1;// 消息分n塊后總的開銷; // n個ChunkBasicHeader 1個ChunkMsgHeader 1個Message負載;// 實際上只有第一個Chunk是完整的,剩下的只有ChunkBasicHeader;tlen = chunks * (cSize + 1) + nSize + hSize;tbuf = malloc(tlen);if (!tbuf){return FALSE;}toff = tbuf;}}// 消息的負載 + 頭;while (nSize + hSize){int wrote;// 消息負載大小 < Chunk大小(不用分塊);if (nSize < nChunkSize){// Chunk可能小于設定值;nChunkSize = nSize; }RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)header, hSize);RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)buffer, nChunkSize);// 若是r->Link.protocol采用Http協議 則將RTMP包數據封裝成多個Chunk 而后一次性發送; // 不然每封裝成一個塊,就當即發送出去;if (tbuf){// 將從Chunk頭開始的nChunkSize + hSize個字節拷貝至toff中;// 這些拷貝的數據包括塊頭數據(hSize字節)和nChunkSize個負載數據;memcpy(toff, header, nChunkSize + hSize);toff += nChunkSize + hSize;}else// 負載數據長度不超過設定的塊大小 不須要分塊; 所以tbuf為NULL或者r->Link.protocol不采用Http;{// 直接將負載數據和塊頭數據發送出去;wrote = WriteN(r, header, nChunkSize + hSize);if (!wrote){return FALSE;}}nSize -= nChunkSize; // 消息負載長度 - Chunk負載長度;buffer += nChunkSize; // buffer指針前移1個Chunk負載長度;hSize = 0;// 若是消息負載數據尚未發完 準備填充下一個塊的塊頭數據; if (nSize > 0){header = buffer - 1;hSize = 1;if (cSize){header -= cSize;hSize += cSize;}*header = (0xc0 | c);if (cSize){int tmp = packet->m_nChannel - 64;header[1] = tmp & 0xff;if (cSize == 2){header[2] = tmp >> 8;}}}}if (tbuf){int wrote = WriteN(r, tbuf, toff-tbuf);free(tbuf);tbuf = NULL;if (!wrote){return FALSE;}}/* we invoked a remote method */if (packet->m_packetType == RTMP_PACKET_TYPE_INVOKE){AVal method;char *ptr;ptr = packet->m_body + 1;AMF_DecodeString(ptr, &method);RTMP_Log(RTMP_LOGDEBUG, "Invoking %s", method.av_val);/* keep it in call queue till result arrives */if (queue){int txn;ptr += 3 + method.av_len;txn = (int)AMF_DecodeNumber(ptr);AV_queue(&r->m_methodCalls, &r->m_numCalls, &method, txn);}}if (!r->m_vecChannelsOut[packet->m_nChannel]){r->m_vecChannelsOut[packet->m_nChannel] = malloc(sizeof(RTMPPacket));}memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet, sizeof(RTMPPacket));return TRUE; }

wireshark抓包結果:

源碼下載地址:?https://github.com/kingsunc/RTMP_Test

總結

以上是生活随笔為你收集整理的librtmp源码详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

日本精品一区二区 | 爱av在线网| 国产精品免费观看在线 | 亚洲国产激情 | 天天干天天看 | 免费视频久久久久 | 91视频电影 | 91成人免费看 | 国产在线第三页 | 午夜av在线免费 | 免费在线观看污网站 | 午夜精品视频一区二区三区在线看 | 亚洲精品 在线视频 | 黄色成人在线网站 | 中文字幕第一页在线播放 | 天天干中文字幕 | 久久不射影院 | 992tv又爽又黄的免费视频 | 中文字幕免费国产精品 | 右手影院亚洲欧美 | 欧美激情视频一区二区三区 | 视频在线国产 | 欧美性网站 | 久久久久亚洲精品男人的天堂 | 特级毛片aaa | 国产精品麻豆三级一区视频 | 天堂视频中文在线 | 丁香婷婷久久久综合精品国产 | 国产精品久久久久久久久久东京 | 免费网站在线观看成人 | 日韩精品一区电影 | 国产另类av | 日韩中文字幕免费在线播放 | 久久中文精品视频 | 国产区 在线 | 丁香久久综合 | 在线观看911视频 | 制服丝袜一区二区 | 久久伊人免费视频 | 日韩高清精品免费观看 | 丁香九月激情综合 | 91视频中文字幕 | 成人精品视频久久久久 | 爱情影院aqdy鲁丝片二区 | 国产在线观看91 | av电影在线不卡 | 在线观看国产日韩 | a在线v| 国产精品一区二区av影院萌芽 | 色视频网站在线观看一=区 a视频免费在线观看 | 久久伊人热 | 久久伦理 | 色噜噜在线观看 | av电影免费看 | 亚洲在线视频免费观看 | 日韩免 | 国产精品高清在线 | 久久久精品 一区二区三区 国产99视频在线观看 | 亚洲影音先锋 | 久久婷婷亚洲 | 91av社区 | 少妇bbw搡bbbb搡bbb | 国产一区二区三区网站 | 成人在线免费看视频 | 黄色大片日本免费大片 | 久久这里有精品 | 久久男人中文字幕资源站 | 最新动作电影 | 日本巨乳在线 | 美女久久一区 | 九月婷婷色 | 国产精品久久精品 | 夜夜骑首页 | 天天操天天射天天操 | 超碰大片| 欧美亚洲一区二区在线 | 人人草在线视频 | 成人午夜网 | 最近中文字幕免费大全 | 午夜精品久久久99热福利 | 亚洲欧洲精品一区 | 不卡电影一区二区三区 | 福利片视频区 | 日韩精品第一区 | av一级久久| 一级黄网| 久九视频 | 亚洲精品美女在线观看播放 | 日本黄色免费电影网站 | 国产理论一区二区三区 | 亚洲综合欧美精品电影 | 日韩美精品视频 | 免费观看十分钟 | 91av中文字幕| 国产免费亚洲高清 | 丁香久久 | 最新国产精品亚洲 | 中文字幕最新精品 | 特级西西444www大胆高清无视频 | 欧美精品生活片 | 日本三级吹潮在线 | 欧美色图88| 欧洲在线免费视频 | 国产精品久久久久久久久久新婚 | 精品日韩在线一区 | 精品欧美一区二区在线观看 | 国产 在线 日韩 | 日韩中文字幕在线观看 | 久久久亚洲麻豆日韩精品一区三区 | 99久久99久久精品 | 一区二区三区免费在线观看视频 | 97精品国产97久久久久久粉红 | 成人免费在线网 | 久久久国产99久久国产一 | 婷婷视频在线观看 | 亚洲精品在线二区 | 亚洲成人资源在线观看 | 一级a性色生活片久久毛片波多野 | www.日本色| 久久久久久久久久久国产精品 | 中文字幕中文字幕中文字幕 | 久二影院 | 精品国产一区二区三区在线 | av在线免费观看网站 | 日韩在线精品一区 | 久久久私人影院 | 国产日韩视频在线 | 毛片网站观看 | 久久精品一区二区三 | 久一网站| www·22com天天操| 日韩欧美在线国产 | 四虎国产精 | 欧美成人黄色片 | 免费看一级特黄a大片 | 久久久免费少妇 | 国产精品 日韩精品 | 亚洲精品网页 | 五月花丁香婷婷 | 国产国语在线 | 日韩欧美在线观看一区 | 亚洲精品综合一区二区 | 精久久久久 | 五月婷婷开心中文字幕 | 精品国产视频一区 | 国产99久久久精品视频 | 亚洲成av | 精品久久久久免费极品大片 | 天天干天天干天天干天天干天天干天天干 | 中文字幕在线观看视频一区 | 欧美日韩亚洲国产一区 | 久久九九九九 | 免费在线观看国产精品 | 91免费网站在线观看 | 欧美一级xxxx | 亚洲精品在线视频网站 | 国产亚洲精品精品精品 | 在线a视频| 日韩久久精品一区二区三区 | 免费污片 | 成人av在线观 | 国产青青青 | 免费观看9x视频网站在线观看 | 九九免费精品视频在线观看 | 91av在| 91av原创 | 天天干天天摸 | 亚洲毛片视频 | 国内毛片毛片 | 色a4yy| 综合色爱| 天天操天天操天天干 | 久久久久久久久久久免费视频 | 一本一道久久a久久精品 | 国产精品视频最多的网站 | 久久这里有精品 | 日韩电影在线视频 | 成人在线免费视频 | 国产一区二区在线免费视频 | 99久久久久免费精品国产 | 婷婷丁香av| 久久精品99国产精品日本 | 婷婷九月激情 | 久久综合九色 | 国产在线精品二区 | 日韩女同一区二区三区在线观看 | www91在线观看 | 精品久久在线 | 国产精品久久久久久久午夜片 | 日日夜夜国产 | www成人精品 | 久久综合久久综合久久综合 | 精品免费国产一区二区三区四区 | 久久97超碰 | 国产成人无码AⅤ片在线观 日韩av不卡在线 | 69国产成人综合久久精品欧美 | 黄色毛片一级 | 亚洲欧美日韩不卡 | 日本三级国产 | 午夜神马福利 | 亚洲国产精品电影在线观看 | 区一区二区三在线观看 | 久精品视频在线观看 | 国产综合在线观看视频 | 日韩专区一区二区 | 亚洲精品在线看 | 久久电影中文字幕视频 | 国产在线欧美 | 久久国产精品99久久久久久老狼 | www.黄色在线 | 激情av在线播放 | 久久久午夜视频 | 91av精品 | 精品久久精品久久 | 狠狠干夜夜 | 成人av电影在线播放 | 日韩理论片在线观看 | 日本夜夜草视频网站 | 国产精品麻豆果冻传媒在线播放 | 玖玖在线资源 | 91精品国产91热久久久做人人 | 久久精品99国产精品亚洲最刺激 | 天天综合网国产 | 美女网站视频免费都是黄 | 丁香5月婷婷久久 | 激情偷乱人伦小说视频在线观看 | 日韩激情一二三区 | 亚洲在线综合 | 色噜噜狠狠色综合中国 | 91成版人在线观看入口 | 精品v亚洲v欧美v高清v | 最近中文字幕在线 | 国产在线观看午夜 | av成人资源 | 精品国产成人在线 | 日韩美一区二区三区 | 欧美日韩性生活 | 手机看国产毛片 | 中文字幕国内精品 | 亚洲 中文 欧美 日韩vr 在线 | 国产一区视频在线观看免费 | 国产一区二区电影在线观看 | 丝袜少妇在线 | 亚洲一区二区三区毛片 | 九九视频免费观看视频精品 | 国产精品久久久久永久免费观看 | 日韩免费视频网站 | 国模吧一区| 国产99久久精品一区二区永久免费 | 99热只有精品在线观看 | 天天操天天干天天操天天干 | 国产18精品乱码免费看 | 国产麻豆精品久久一二三 | 欧美视频一区二 | 久久av网| 天天操比 | 日日夜夜网 | 爱爱av在线 | 欧美性春潮 | 中文字幕一区2区3区 | 日本精品二区 | 欧美综合色在线图区 | 中文字幕在线观看免费高清完整版 | 91麻豆精品| 天天激情天天干 | 久久精品久久精品久久39 | 色偷偷中文字幕 | 久在线观看视频 | 人人玩人人添人人澡超碰 | 国产破处在线播放 | 激情伊人五月天久久综合 | 国模一区二区三区四区 | 日韩免费在线视频 | 国产一级高清 | 中国一区二区视频 | 欧美成人区 | 1024在线看片 | 国产黄色理论片 | 国产精品www| 麻豆91在线 | 国产精品三级视频 | 最新中文字幕在线播放 | 五月黄色 | 在线观看日韩精品 | 日韩一区在线免费观看 | 午夜精品久久久久久久久久久久久久 | 丁香六月中文字幕 | av在线免费播放 | 免费在线观看的av网站 | 亚洲毛片久久 | 日本久久精品 | 国产在线精品一区二区三区 | 久草久热| 亚洲黄色av网址 | 成人中文字幕+乱码+中文字幕 | 亚洲另类人人澡 | 香蕉网站在线观看 | 国产五月色婷婷六月丁香视频 | 最近中文字幕在线播放 | 激情久久网 | 国产在线精品一区二区 | 免费看成年人 | 中文字幕超清在线免费 | 国产精品久久久久aaaa九色 | www天天干com| 日韩成人高清在线 | 国产日韩视频在线观看 | 国产成人精品av在线观 | 色九九在线 | 夜夜爽88888免费视频4848 | 高清日韩一区二区 | 久久首页 | av成人免费在线观看 | 天天摸天天舔 | 午夜国产影院 | 曰韩精品 | 人人爽人人澡人人添人人人人 | 91亚色免费视频 | 99在线精品视频在线观看 | 久久久精品国产一区二区 | 日本成人中文字幕在线观看 | 久久国产亚洲视频 | 天天插综合网 | 色视频网站在线 | 国产精品9999久久久久仙踪林 | 久久久久久久久久久影视 | av在线播放观看 | 91av在线精品 | 五月天激情综合 | 免费a网址 | 麻豆视频免费在线观看 | 久久久久久久99 | 国产精品久久久久久久妇 | 欧美黄色高清 | 亚洲精品黄色片 | 欧美性色19p | 国产日韩精品久久 | 蜜桃麻豆www久久囤产精品 | av丝袜天堂| 成人在线观看资源 | 亚洲精品日韩一区二区电影 | 国产成人一区二区三区久久精品 | 欧美最爽乱淫视频播放 | 99精品国产高清在线观看 | 午夜精品区 | 人人爱人人舔 | 99精品在线观看视频 | 久久精品牌麻豆国产大山 | 欧美日韩天堂 | 欧美日韩调教 | 美女网站色在线观看 | 久久黄色片 | 欧美在线视频一区二区三区 | 波多野结衣资源 | 国产精品成人国产乱一区 | 亚洲成av人片在线观看无 | 欧美日产一区 | 中文字幕在线观看视频一区 | 国产日韩欧美精品在线观看 | av黄网站 | 特级黄录像视频 | 麻豆国产在线视频 | www.夜夜| 狠狠色噜噜狠狠狠狠2021天天 | 国产精品久久一区二区无卡 | 日韩免费三区 | 西西4444www大胆视频 | 精品国产福利在线 | 久久免费视频精品 | 97在线精品| 中文字幕第 | 色妞久久福利网 | 人人狠狠综合久久亚洲 | 99精品视频在线观看 | 国产免费av一区二区三区 | 国产不卡毛片 | 狠狠色丁香婷婷综合最新地址 | 国产精品99在线观看 | 欧美影片 | 亚洲国产一区二区精品专区 | 亚洲精品乱码白浆高清久久久久久 | 激情黄色av| 麻豆传媒视频在线播放 | 欧美 国产 视频 | 92国产精品久久久久首页 | 欧美日韩网址 | 日韩午夜小视频 | 美女露久久 | 国产精品久久久电影 | 婷婷久久丁香 | 狠狠干干 | www色片 | 天天干天天做天天爱 | 一区二区电影在线观看 | 午夜久久福利视频 | av电影在线播放 | 永久黄网站色视频免费观看w | 中文资源在线播放 | 国产一级片免费播放 | 中文字幕成人网 | 国产精品一区二区久久国产 | 免费在线观看国产精品 | 久久永久免费视频 | 日韩国产精品久久 | 欧美国产精品久久久久久免费 | 精品国产一区二区三区四区在线观看 | 国产成人久久精品77777综合 | 国产精品视频在线观看 | 夜夜嗨av色一区二区不卡 | 欧美淫aaa免费观看 日韩激情免费视频 | 91久久久久久国产精品 | 欧美久久成人 | 天天色天天草天天射 | 久久爱影视i | 最新国产精品久久精品 | 五月婷丁香 | 国产精品理论片在线播放 | 亚洲乱码在线观看 | 国产精品久久嫩一区二区免费 | 国产精品岛国久久久久久久久红粉 | 日产乱码一二三区别在线 | 91资源在线免费观看 | 开心激情久久 | 日韩二区在线播放 | 一级成人免费视频 | 久久久精品免费观看 | 在线免费成人 | 日韩在线精品一区 | 国产成人精品久久亚洲高清不卡 | 久久精品精品 | 久久免费黄色大片 | 国产精品一区在线观看 | 亚洲高清视频在线观看 | 99国产精品久久久久久久久久 | 99久久久久| 欧美激情精品久久久久久免费印度 | 丁香婷婷色月天 | 欧美日韩在线观看不卡 | wwxxx日本| 草久视频在线 | av电影中文字幕在线观看 | 亚洲天堂网在线观看视频 | 日本激情视频中文字幕 | 国产中文字幕在线观看 | 日韩免费在线看 | av电影在线不卡 | 色九九影院 | 伊人五月婷 | av在线电影网站 | 午夜精品久久久久久久99婷婷 | 国产精品毛片一区视频播 | 波多野结衣电影一区 | av东方在线| 成人蜜桃视频 | 精品国产一区二区三区久久久久久 | 日韩免费视频在线观看 | 免费观看www7722午夜电影 | 在线观看国产一区二区 | 日本成址在线观看 | 国产精品免费看 | 久久久久久久久影院 | 又黄又爽又刺激的视频 | 日韩精品一区二区免费视频 | 亚洲欧美日韩国产一区二区 | 亚洲男模gay裸体gay | 婷婷免费在线视频 | 中文字幕在线国产精品 | 久久久在线免费观看 | 久草在在线视频 | 亚洲视频专区在线 | 婷婷亚洲综合五月天小说 | 日韩欧美高清视频在线观看 | h文在线观看免费 | 亚洲精品久久久蜜桃 | 日韩电影中文,亚洲精品乱码 | 国产精品视频免费在线观看 | 在线视频久 | 日韩二区三区 | 久久超碰免费 | 久久夜色精品国产欧美乱极品 | 日韩av资源站 | 日韩av在线不卡 | 日韩av在线高清 | 国产大片免费久久 | av中文字幕电影 | 午夜视频在线观看欧美 | 国产精品一区二区免费看 | av蜜桃在线 | 国产精品毛片久久蜜 | 超碰成人免费电影 | 中文字幕 国产 一区 | 在线观看视频中文字幕 | 国产视频在线一区二区 | 国产乱码精品一区二区三区介绍 | 欧洲亚洲激情 | 免费在线黄网 | 丝袜美腿av| 欧美日韩中文字幕视频 | 久草在线免费资源 | www.在线看片.com | 久久精品久久99 | 97在线视频网站 | 久久综合色一综合色88 | 免费观看全黄做爰大片国产 | 福利一区二区 | 国产成人亚洲在线观看 | 天天玩天天操天天射 | 久久999精品 | 国产麻豆成人传媒免费观看 | 成人禁用看黄a在线 | 国产护士hd高朝护士1 | 国产成人精品av在线 | 日日夜夜人人天天 | 在线国产日韩 | 国产精品高清免费在线观看 | 国产精品毛片久久久久久久 | 国产视频二区三区 | 最近免费中文字幕 | 超碰精品在线观看 | 丁香花中文字幕 | 99精品偷拍视频一区二区三区 | 黄污网站在线观看 | 91福利视频网站 | 97人人网| 98涩涩国产露脸精品国产网 | www.天天射 | 黄色在线观看免费 | 欧美少妇xxx| 国产精品乱码久久久久久1区2区 | 天天天综合网 | 国产精品国产三级国产aⅴ无密码 | 国产视频一区在线免费观看 | av在线专区 | 久久久18 | 久草久热 | 日韩免费网址 | 国产亚洲成人精品 | 中文字幕资源在线 | 国产午夜麻豆影院在线观看 | 国产不卡视频在线播放 | 中文字幕美女免费在线 | 三级av网站 | av大全免费在线观看 | 精品一区在线看 | 亚洲国产精品人久久电影 | 日韩免 | 日韩三级精品 | 丝袜美女在线观看 | 国产精品成人自产拍在线观看 | av福利在线 | 午夜视频在线网站 | 欧美日韩国产二区 | 在线观看中文字幕av | 激情综合网色播五月 | 久影院 | 日韩欧美网站 | 国产成人精品免费在线观看 | 日韩精品久久久久久 | 狠狠色噜噜狠狠狠狠2021天天 | 久久成人国产精品入口 | 9999在线视频 | 国产精品乱码久久久久久1区2区 | 怡红院成人在线 | 国产黑丝一区二区 | 夜色资源站国产www在线视频 | 久草在线综合 | 天天干天天插伊人网 | 久久新 | 国产精品欧美一区二区 | 亚洲免费av电影 | 成人h在线播放 | av经典在线 | 色在线国产 | 日本三级吹潮在线 | 国产精品1区2区在线观看 | 婷婷国产v亚洲v欧美久久 | 日韩免费三级 | 国产福利精品视频 | 在线a亚洲视频播放在线观看 | av一级在线观看 | 精品毛片久久久久久 | 中文字幕九九 | 一本色道久久精品 | 97视频播放 | 日韩专区中文字幕 | 中文字幕区| 日韩性片 | 91在线成人 | 91禁看片| 天天躁日日躁狠狠躁av中文 | 国产精品视频你懂的 | 黄色av免费在线 | 国产精品久久久区三区天天噜 | 久久精品欧美一 | 精品国产一区二区三区噜噜噜 | 五月天伊人网 | 日韩激情精品 | 亚洲日本精品 | 国产精品精品久久久久久 | 日韩av一区二区三区四区 | 久久精品8| 久久99精品热在线观看 | 国产 字幕 制服 中文 在线 | 日本中文字幕一二区观 | 99久久精品电影 | 91精品国产乱码久久桃 | 中文亚洲欧美日韩 | 99精品国产福利在线观看免费 | 午夜视频一区二区 | 国产精品永久在线 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 91正在播放 | 激情视频网页 | 色婷婷a| 国内精品久久久久久久久久久 | av丁香花 | 亚洲成av人影院 | 国产激情久久久 | 91在线欧美| 日本精品一区二区三区在线播放视频 | 中文字幕在线观看网站 | 久久久免费精品视频 | 激情 婷婷| 五月婷婷中文网 | 在线国产视频观看 | 国产精品不卡一区 | 毛片1000部免费看 | 国产精品区免费视频 | 国产黄色免费电影 | 蜜臀av夜夜澡人人爽人人桃色 | 丁香六月婷婷激情 | 久久国产热 | 99在线观看精品 | 99热这里是精品 | 国产黄av | 一区二区三区高清不卡 | 久久超碰网 | 国产成人av电影 | 久草免费电影 | 国产精品免费在线观看视频 | 成人中文字幕+乱码+中文字幕 | 国产麻豆精品传媒av国产下载 | 国产精品久久久久免费观看 | 91av在线免费播放 | 碰碰影院| 午夜久久成人 | 欧美在线视频免费 | av片在线看 | 偷拍精品一区二区三区 | 亚洲一区尤物 | 免费能看的黄色片 | 在线国产能看的 | 在线之家官网 | 国产精品麻豆91 | 91九色蝌蚪视频 | 成人在线免费看视频 | 亚洲电影第一页av | 亚洲天堂网在线观看视频 | 美女久久久 | 国产精品视频线看 | 黄色软件在线观看免费 | 欧美色久| 91精品视频一区 | 久久综合免费视频影院 | 天天草天天草 | 黄色aaaaa| 五月婷婷综合在线视频 | 一级免费看 | 四虎在线观看精品视频 | 黄色网址中文字幕 | 国产高清专区 | 97天堂网| 日韩一区二区三区观看 | 999国产精品视频 | 国内丰满少妇猛烈精品播 | av在线播放观看 | 99精品一区二区 | 亚洲免费小视频 | 美女视频黄频大全免费 | 精品一二| 精品伦理一区二区三区 | 国产乱老熟视频网88av | 成人黄色大片网站 | av解说在线| 国产精品自拍av | av免费观看高清 | 曰韩在线| 狠狠的日| 天干啦夜天干天干在线线 | 日韩精品久久中文字幕 | 日韩欧美国产精品 | 欧美色图视频一区 | 成人午夜剧场在线观看 | 91亚洲国产 | 免费观看十分钟 | 91视频首页 | 婷婷久久国产 | 一区二区三区观看 | 日韩艹| 日韩欧美在线观看一区二区 | 国产美女免费观看 | 国内精品久久久久久久97牛牛 | 日韩欧美在线影院 | 日本韩国中文字幕 | 国产精品一码二码三码在线 | av理论电影 | 精品久久中文 | 天堂av在线免费 | 日韩精品一区二区三区水蜜桃 | 久久高清精品 | 国产一级视频免费看 | 国产专区一 | 国产精国产精品 | 国产精品综合久久久久 | 国产高清在线永久 | 亚洲 欧美 变态 国产 另类 | 麻豆免费视频 | 日日碰夜夜爽 | 在线一区电影 | 亚洲黄污 | 精品女同一区二区三区在线观看 | 人人爽人人爽人人爽人人爽 | 999国产精品视频 | www欧美日韩 | 国产精品久久久久影院 | 日韩69视频 | 天海翼一区二区三区免费 | 中文字幕 国产精品 | 成人激情开心网 | 日韩成人免费在线观看 | 婷婷丁香色 | 成年人免费观看在线视频 | 欧美日韩高清在线一区 | 91精品国自产拍天天拍 | 国产网红在线 | 色香蕉在线 | 日日夜夜天天射 | 免费进去里的视频 | 天天操天天干天天插 | 欧美色插 | 免费在线 | 超碰97在线资源站 | 五月天免费网站 | 亚洲精品91天天久久人人 | 日韩精品亚洲专区在线观看 | 在线播放日韩 | 国产专区精品 | 精品国产aⅴ一区二区三区 在线直播av | 成人免费视频观看 | 草久久精品 | 999久久久| 亚洲欧美婷婷六月色综合 | 欧美韩日在线 | 91人网站| 99在线精品视频 | 蜜臀av性久久久久av蜜臀妖精 | 日韩免费视频网站 | 97人人视频 | 国产精品久久一区二区三区不卡 | 在线日韩一区 | 亚洲国产资源 | 99中文字幕视频 | 国内丰满少妇猛烈精品播 | 婷婷丁香花五月天 | 日韩欧美在线视频一区二区 | 99久久er热在这里只有精品15 | 精品一二三四五区 | 久久国产热视频 | 亚洲综合成人专区片 | 成人在线视频论坛 | av免费试看 | 亚洲国产日韩一区 | 不卡的av电影 | 激情影院在线 | 久草网在线| 午夜电影av| 久久免费av电影 | 激情视频在线高清看 | 在线观看视频一区二区三区 | 91久久一区二区 | 国产成人久久av免费高清密臂 | 99久久精| 国产 中文 日韩 欧美 | 99在线观看精品 | 久久精品香蕉视频 | 天天草天天摸 | 婷婷午夜 | 射射射综合网 | av黄色免费看 | 中文字幕在线影院 | 久久久久久综合 | 天天操夜夜看 | 欧美成天堂网地址 | 在线观看视频黄色 | 国产成人亚洲在线电影 | 97电影网手机版 | 国产精品久久久久久电影 | 91亚洲精品国偷拍自产在线观看 | 天天在线免费视频 | 又黄又爽又无遮挡免费的网站 | 亚洲精品人人 | 久久网站最新地址 | 香蕉国产91| 五月婷婷操 | 久久久国产精品成人免费 | 日韩一区二区三区免费视频 | 国产永久网站 | 91精品视频一区二区三区 | 四虎亚洲精品 | 亚洲精品在线二区 | 日本中文在线观看 | 欧美福利视频一区 | 中文永久免费观看 | 依人成人综合网 | 精品自拍网 | 成人免费一区二区三区在线观看 | 国产自在线 | 亚州激情视频 | 中文在线√天堂 | 在线观看蜜桃视频 | 久九视频| 国产精品免费观看在线 | 狠狠做深爱婷婷综合一区 | 粉嫩av一区二区三区四区在线观看 | 人人看人人爱 | 一区二区三区在线免费 | 夜夜操综合网 | 欧美成人视 | 欧美国产日韩中文 | 亚洲色图27p| 一本一道久久a久久精品 | 亚洲免费专区 | 色亚洲网 | 狠狠干网站 | 99综合影院在线 | 亚洲色图av | 91桃色视频| 成年人黄色在线观看 | 亚洲国产中文字幕在线观看 | 人人爽人人澡人人添人人人人 | 国产电影一区二区三区四区 | 国产午夜视频在线观看 | 亚洲欧美精品在线 | 五月综合激情婷婷 | 久草在线手机视频 | 久久99精品久久久久蜜臀 | 中文字幕在线中文 | 天天操天天射天天插 | 一区二区三区免费看 | 久久精品视频在线播放 | 在线观看精品黄av片免费 | 欧美日韩视频在线观看一区二区 | 久草视频在线看 | 亚洲黄色网络 | 久久久96| 在线免费91 | 欧美日韩国产综合网 | 国产毛片久久 | 日韩免费在线观看视频 | 国产一区网址 | 国产无套一区二区三区久久 | 国产免费二区 | 香蕉免费在线 | 99热最新在线| 狠狠色伊人亚洲综合网站野外 | 国产精品色婷婷视频 | 久久国产香蕉视频 | 久久久国际精品 | 久久久久久蜜av免费网站 | 亚洲精品自拍视频在线观看 | 国产69熟| 亚洲视频专区在线 | 天天操夜夜操 | 高清视频一区 | 免费高清看电视网站 | 亚洲精品国偷拍自产在线观看蜜桃 | 亚洲精品永久免费视频 | 中文字幕美女免费在线 | 97视频在线观看播放 | 国产手机视频在线 | 亚洲激情五月 | 亚洲欧美怡红院 | 国产中文字幕91 | 亚洲天堂网视频 | 免费观看国产成人 | 成人精品视频 | 国产一区二区在线免费视频 | 国产资源在线观看 | 91日韩免费 | 免费看的黄色 | 日韩av三区 | 国产精品一区在线观看 | 亚洲区另类春色综合小说 | 欧美激情另类文学 | 在线看日韩 | 综合色中文 | 国产精品美女久久久久久久 | 一区二区中文字幕在线播放 | 免费看的黄色网 | 美女黄网站视频免费 | 不卡av电影在线观看 | 欧美精品亚洲精品 | 在线观看中文字幕第一页 | 99久久精品免费看国产免费软件 | 999久久久久久久久6666 | 色综合天天色 | 久草com| 91亚洲精品在线观看 | 欧产日产国产69 | 人人干网站 | 亚洲毛片在线观看. | 91成人精品在线 | 久久免费福利视频 | 亚洲国产网址 | 欧美日韩久久不卡 | 九九视频在线观看视频6 | 99免费在线视频观看 | av成人亚洲| 成人午夜网 | 欧美九九九 | 黄色精品久久 | 国内精品久久久久久久久久清纯 | 婷婷丁香在线观看 | 色搞搞| 久久精品欧美一区二区三区麻豆 | 久久99精品国产99久久 | 91欧美精品 | 欧美日韩视频在线播放 | 国产不卡精品 | 91免费观看视频在线 | av网站有哪些 | 免费高清在线观看电视网站 | 欧美视频一区二 | 97超碰人人澡人人爱学生 | 亚洲国产网址 | 91网站在线视频 | adc在线观看 | 中文字幕麻豆 | 国偷自产中文字幕亚洲手机在线 | 中文字幕电影在线 | 四虎在线免费观看视频 | 久久久久综合精品福利啪啪 | 亚洲精品国偷拍自产在线观看蜜桃 | 97视频久久久 | 国产不卡网站 | 午夜国产一区 | 丁香花在线观看免费完整版视频 | 91激情在线视频 | 精品久久久久久亚洲综合网站 | 久久久免费高清视频 | 中文字幕一区二区三区在线观看 | 欧美婷婷色 | 国产成人精品999在线观看 | 久久这里只有精品久久 | 亚洲视频www | 9在线观看免费 | 免费av网站观看 | 日本黄区免费视频观看 | 国产一区二区三区黄 | 最新国产中文字幕 | 久久精品—区二区三区 | 888av| 久久99欧美| japanesexxxxfreehd乱熟 | 国产精品久久一区二区三区, | 欧美极度另类性三渗透 | 国产h片在线观看 | 色婷婷亚洲精品 | 久久精品成人热国产成 | 一区二区三区不卡在线 | 日韩激情免费视频 | 最新日韩中文字幕 | 992tv在线| 成人a级黄色片 | 黄色免费网站下载 | 婷婷在线免费观看 | 免费高清无人区完整版 | 一色av | 天天综合91 | 国产色综合天天综合网 | 日韩大片在线观看 | 91av大全| 久久情侣偷拍 | 欧美在线你懂的 | 欧美色就是色 | 中文字幕影片免费在线观看 | 国产一级在线观看 | 中文字幕黄色网址 | 久久蜜臀av | 黄色在线观看免费 | 香蕉网站在线观看 | 三级av中文字幕 | 免费麻豆网站 | 亚洲国产高清在线观看视频 | 免费视频三区 | 国产一级片一区二区三区 | 婷婷色网站 | 亚洲成人网在线 |