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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

网络摄像头Rtsp直播方案(二)

發布時間:2023/12/14 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络摄像头Rtsp直播方案(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上一部分說了Socket通訊的一些東西,這部分就結合代碼來說說RTSP交互的過程。
在放實現代碼之前先說說概念上的東西吧,關于RTSP這個流媒體網絡協議。RTSP作為一個應用層協議,提供了一個可供擴展的框架,使得流媒體的受控和點播變得可能,它主要用來控制具有實時特性的數據的發送,但其本身并不用于傳送流媒體數據,而必須依賴下層傳輸協議(如RTP/RTCP)所提供的服務來完成流媒體數據的傳送。RTSP負責定義具體的控制信息、操作方法、狀態碼,以及描述與RTP之間的交互操作。所以具體的碼流數據其實是用RTP封裝傳輸的,第三部分我會詳細講碼流數據的處理和發送。


一次基本的RTSP交互過程如上圖所示,C表示客戶端即請求碼流的用戶,S為服務器即網絡攝像機。
首先客戶端連接到流媒體服務器并發送一個RTSP描述請求(DESCRIBE request),服務器通過一個SDP(Session DescriptionProtocol)描述來進行反饋(DESCRIBEresponse),反饋信息包括流數量、媒體類型等信息。客戶端分析該SDP描述,并為會話中的每一個流發送一個RTSP連接建立請求(SETUPrequest),該命令會告訴服務器用于接收媒體數據的端口,服務器響應該請求(SETUP response)并建立連接之后,就開始傳送媒體流(RTP包)到客戶端。在播放過程中客戶端還可以向服務器發送請求來控制快進、快退和暫停等。最后,客戶端可發送一個終止請求(TEARDOWN request)來結束流媒體會話。

RTSP最基本的東西就是這些,其他復雜的東西我也不想說太多了,有興趣的可以查查RFC2326(假裝復雜的東西我懂似的),OK,講代碼。上一部分我放了我main函數寫的東西,在tcp_listen()這個函數之后我建立了一個Socket連接,并把套接字傳到了EventLoop()這個函數里面,上面說了RTSP并不負責傳輸具體視音頻數據,這部分是由RTP傳輸的,所以在tcp_listen建立的套接字是用來做RTSP消息傳輸的這里的SOCKET是TCP,后面我還會再建立新的UDP SOCKET用以傳輸具體的視頻數據,這個具體后面會說這里提一句。

static int s32ConCnt = 0;//已經連接的客戶端數int s32Fd = -1;static RTSP_buffer *pRtspList=NULL;RTSP_buffer *p=NULL;unsigned int u32FdFound;/*接收連接,創建一個新的socket*/if (s32ConCnt!=-1){s32Fd= tcp_accept(s32MainFd);}/*處理新創建的連接*/if (s32Fd >= 0){/*查找列表中是否存在此連接的socket*/for (u32FdFound=0,p=pRtspList; p!=NULL; p=p->next){if (p->fd == s32Fd){printf("### exit socket Fd ###\n");u32FdFound=1;break;}}if (!u32FdFound){/*創建一個連接,增加一個客戶端*/if (s32ConCnt<MAX_CONNECTION){++s32ConCnt;AddClient(&pRtspList,s32Fd);}else{fprintf(stderr, "exceed the MAX client, ignore this connecting\n");return;}num_conn++;fprintf(stderr, "%s Connection reached: %d\n", __FUNCTION__, num_conn);}}/*對已有的連接進行調度*/ScheduleConnections(&pRtspList,&s32ConCnt);

上面是EventLoop()函數的源碼,講一下RTSP_buffer這個結構體,定義在下面。因為這個直播是一對多的場景,即一個攝像頭,多個用戶同時觀看,所以注定連接數肯定是大于1的,那么,多一個連接,這個新的連接的套接字等信息肯定也不一樣,所以將每一個連接的屬性做一個統一的結構體,且設置為鏈表的結構便于處理。

typedef struct _RTSP_buffer {int fd; /*socket文件描述符*/unsigned int port;/*端口號*/struct sockaddr stClientAddr;char in_buffer[RTSP_BUFFERSIZE];/*接收緩沖區*/unsigned int in_size;/*接收緩沖區的大小*/char out_buffer[RTSP_BUFFERSIZE+MAX_DESCR_LENGTH];/*發送緩沖區*/int out_size;/*發送緩沖區大小*/unsigned int rtsp_cseq;/*序列號*/char descr[MAX_DESCR_LENGTH];/*描述*/RTSP_session *session_list;/*會話鏈表*/struct _RTSP_buffer *next; /*指向下一個結構體,構成了鏈表結構*/ } RTSP_buffer;

OK,EventLoop()這個函數我們可以看出來首先是判斷是不是一個新的套接字:

  • 如果是一個新的套接字,給這個新的套接字建立一個新的連接,即加一個客戶端。進到AddClient()函數
  • RTSP_buffer *pRtsp=NULL,*pRtspNew=NULL;#ifdef RTSP_DEBUGfprintf(stderr, "%s, %d\n", __FUNCTION__, __LINE__); #endif//在鏈表頭部插入第一個元素if (*ppRtspList==NULL){/*分配空間*/if ( !(*ppRtspList=(RTSP_buffer*)calloc(1,sizeof(RTSP_buffer)) ) ){fprintf(stderr,"alloc memory error %s,%i\n", __FILE__, __LINE__);return;}pRtsp = *ppRtspList;}else{//向鏈表中插入新的元素for (pRtsp=*ppRtspList; pRtsp!=NULL; pRtsp=pRtsp->next){pRtspNew=pRtsp;}/*在鏈表尾部插入*/if (pRtspNew!=NULL){if ( !(pRtspNew->next=(RTSP_buffer *)calloc(1,sizeof(RTSP_buffer)) ) ){fprintf(stderr, "error calloc %s,%i\n", __FILE__, __LINE__);return;}pRtsp=pRtspNew->next;pRtsp->next=NULL;}}//設置最大輪詢id號if(g_s32Maxfd < fd){g_s32Maxfd = fd;}/*初始化新添加的客戶端*/RTSP_initserver(pRtsp,fd);fprintf(stderr,"Incoming RTSP connection accepted on socket: %d\n",pRtsp->fd);

    從上面的AddClient()函數我們可以看到其實就是給新的連接的鏈表分配空間,初始化套接字,緩沖區等信息。

    2.如果不是一個新的套接字,即不是新的連接,進到ScheduleConnections()進行已有連接的交互操作

    int res;RTSP_buffer *pRtsp=*rtsp_list,*pRtspN=NULL;RTP_session *r=NULL, *t=NULL;while (pRtsp!=NULL){if ((res = RtspServer(pRtsp))!=ERR_NOERROR){if (res==ERR_CONNECTION_CLOSE || res==ERR_GENERIC){/*連接已經關閉*/if (res==ERR_CONNECTION_CLOSE)fprintf(stderr,"fd:%d,RTSP connection closed by client.\n",pRtsp->fd);elsefprintf(stderr,"fd:%d,RTSP connection closed by server.\n",pRtsp->fd);/*客戶端在發送TEARDOWN 之前就截斷了連接,但是會話卻沒有被釋放*/if (pRtsp->session_list!=NULL){r=pRtsp->session_list->rtp_session;/*釋放所有會話*/while (r!=NULL){t = r->next;RtpDelete((unsigned int)(r->hndRtp));schedule_remove(r->sched_id);r=t;}/*釋放鏈表頭指針*/free(pRtsp->session_list);pRtsp->session_list=NULL;g_s32DoPlay--;if (g_s32DoPlay == 0) {printf("user abort! no user online now resetfifo\n");ringreset();/* 重新將所有可用的RTP端口號放入到port_pool[MAX_SESSION] 中 */RTP_port_pool_init(RTP_DEFAULT_PORT);}fprintf(stderr,"WARNING! fd:%d RTSP connection truncated before ending operations.\n",pRtsp->fd);}// wait forclose(pRtsp->fd);--*conn_count;num_conn--;/*釋放rtsp緩沖區*/if (pRtsp==*rtsp_list){//鏈表第一個元素就出錯,則pRtspN為空printf("first error,pRtsp is null\n");*rtsp_list=pRtsp->next;free(pRtsp);pRtsp=*rtsp_list;}else{//不是鏈表中的第一個,則把當前出錯任務刪除,并把next任務存放在pRtspN(上一個沒有出錯的任務)//指向的next,和當前需要處理的pRtsp中.printf("dell current fd:%d\n",pRtsp->fd);pRtspN->next=pRtsp->next;free(pRtsp);pRtsp=pRtspN->next;printf("current next fd:%d\n",pRtsp->fd);}/*適當情況下,釋放調度器本身*/if (pRtsp==NULL && *conn_count<0){fprintf(stderr,"to stop cchedule_do thread\n");stop_schedule=1;}}else{ printf("current fd:%d\n",pRtsp->fd);pRtsp = pRtsp->next;}}else{//沒有出錯//上一個處理沒有出錯的list存放在pRtspN中,需要處理的任務放在pRtst中pRtspN = pRtsp;pRtsp = pRtsp->next;}}

    上面的源碼主要是循環處理所有RTSP_buffer鏈表中的RTSP報文,具體處理過程在RtspServer()函數中,若其中某個連接有問題就會從鏈表中清除此連接并釋放相關的內存。我們來看看RtspServer():

    fd_set rset,wset; /*讀寫I/O描述集*/struct timeval t;int size;static char buffer[RTSP_BUFFERSIZE+1]; /* +1 to control the final '\0'*/int n;int res;struct sockaddr ClientAddr;if (rtsp == NULL){return ERR_NOERROR;}/*變量初始化*/FD_ZERO(&rset);FD_ZERO(&wset);t.tv_sec=0; /*select 時間間隔*/t.tv_usec=100000;FD_SET(rtsp->fd,&rset);/*調用select等待對應描述符變化*/if (select(g_s32Maxfd+1,&rset,0,0,&t)<0){fprintf(stderr,"select error %s %d\n", __FILE__, __LINE__);send_reply(500, NULL, rtsp);return ERR_GENERIC; //errore interno al server}/*有可供讀進的rtsp包*/if (FD_ISSET(rtsp->fd,&rset)){memset(buffer,0,sizeof(buffer));size=sizeof(buffer)-1; /*最后一位用于填充字符串結束標識*//*讀入數據到緩沖區中*/ #ifdef RTSP_DEBUGfprintf(stderr, "tcp_read, %d\n", __LINE__); #endifn= tcp_read(rtsp->fd, buffer, size, &ClientAddr);if (n==0){return ERR_CONNECTION_CLOSE;}if (n<0){fprintf(stderr,"read() error %s %d\n", __FILE__, __LINE__);send_reply(500, NULL, rtsp); //服務器內部錯誤消息return ERR_GENERIC;}//檢查讀入的數據是否產生溢出if (rtsp->in_size+n>RTSP_BUFFERSIZE){fprintf(stderr,"RTSP buffer overflow (input RTSP message is most likely invalid).\n");send_reply(500, NULL, rtsp);return ERR_GENERIC;//數據溢出錯誤}#ifdef RTSP_DEBUGfprintf(stderr,"INPUT_BUFFER was:%s\n", buffer); #endif/*填充數據*/memcpy(&(rtsp->in_buffer[rtsp->in_size]),buffer,n);rtsp->in_size+=n;//清空buffermemset(buffer, 0, n);//添加客戶端地址信息memcpy( &rtsp->stClientAddr, &ClientAddr, sizeof(ClientAddr));/*處理緩沖區的數據,進行rtsp處理*/if ((res=RTSP_handler(rtsp))==ERR_GENERIC){fprintf(stderr,"Invalid input message.\n");return ERR_NOERROR;}}/*有發送數據*/if (rtsp->out_size>0){//將數據發送出去n= tcp_write(rtsp->fd,rtsp->out_buffer,rtsp->out_size); fprintf(stderr,"S");fflush(stderr);if (n<0){fprintf(stderr,"tcp_write error %s %i\n", __FILE__, __LINE__);send_reply(500, NULL, rtsp);return ERR_GENERIC; //errore interno al server}#ifdef RTSP_DEBUGfprintf(stderr,"OUTPUT_BUFFER length %d\n%s\n", rtsp->out_size, rtsp->out_buffer); #endif//清空發送緩沖區memset(rtsp->out_buffer, 0, rtsp->out_size);rtsp->out_size = 0;}//如果需要RTCP在此出加入對RTCP數據的接收,并存放在緩存中。//繼而在schedule_do線程中對其處理。//rtcp控制處理,檢查讀入RTCP數據報return ERR_NOERROR;

    很熟悉吧?是我們上部分說過的非阻塞的傳輸方式,通過Socket獲取客戶端發過來的rtsp信報,然后將rtsp信報傳到RTSP_handler()函數進行處理

    int s32Meth;while(pRtspBuf->in_size){s32Meth = RTSP_validate_method(pRtspBuf);if (s32Meth < 0){//錯誤的請求,請求的方法不存在fprintf(stderr,"Bad Request %s,%d\n", __FILE__, __LINE__);printf("bad request, requestion not exit %d",s32Meth);send_reply(400, NULL, pRtspBuf);}else{//進入到狀態機,處理接收的請求RTSP_state_machine(pRtspBuf, s32Meth);printf("exit Rtsp_state_machine\r\n");}//丟棄處理之后的消息RTSP_discard_msg(pRtspBuf);printf(" After RTSP_discard_msg\r\n");}return ERR_NOERROR;

    RTSP_validate_method(pRtspBuf)這個函數是通過sscanf()來按格式讀取rtsp數據報,這里簡要分析一下這個函數的一些簡單用法

  • 常見用法。
  • charstr[512]={0};
      sscanf(“123456”,"%s",str);
      printf(“str=%s”,str);

    2. 取指定長度的字符串。如在下例中,取最大長度為4字節的字符串。

    sscanf(“123456”,"%4s",str);
      printf(“str=%s”,str);

    3. 取到指定字符為止的字符串。如在下例中,取遇到空格為止字符串。

    sscanf(“123456abcdedf”,"%[^]",str);
      printf(“str=%s”,str);

    4. 取僅包含指定字符集的字符串。如在下例中,取僅包含1到9和小寫字母的字符串。

    sscanf(“123456abcdedfBCDEF”,"%[1-9a-z]",str);
      printf(“str=%s”,str);

    5. 取到指定字符集為止的字符串。如在下例中,取遇到大寫字母為止的字符串。

    sscanf(“123456abcdedfBCDEF”,"%[^A-Z]",str);
      printf(“str=%s”,str);
     RTSP_validate_method()通過sscanf()這個函數來讀取客戶端rtsp信報中當前的方法來設置狀態并返回。
     這里重點講一下RTSP_state_machine()這個函數,前面獲取的當前方法會傳入這個函數,這函數其實就是一個狀態機,來實現各個方法的回傳的信報拼接并傳回客戶端。

    /*除了播放過程中發送的最后一個數據流,*所有的狀態遷移都在這里被處理* 狀態遷移位于stream_event中*/char *s;RTSP_session *pRtspSess;long int session_id;char trash[255];char szDebug[255];/*找到會話位置*/if ((s = strstr(pRtspBuf->in_buffer, HDR_SESSION)) != NULL){if (sscanf(s, "%254s %ld", trash, &session_id) != 2){fprintf(stderr,"Invalid Session number %s,%i\n", __FILE__, __LINE__);send_reply(454, 0, pRtspBuf); /* 沒有此會話*/return;}}/*打開會話列表*/pRtspSess = pRtspBuf->session_list;if (pRtspSess == NULL){return;}#ifdef RTSP_DEBUGsprintf(szDebug,"state_machine:current state is ");strcat(szDebug,((pRtspSess->cur_state==0)?"init state":((pRtspSess->cur_state==1)?"ready state":"play state")));printf("%s\n", szDebug); #endif/*根據狀態遷移規則,從當前狀態開始遷移*/switch (pRtspSess->cur_state){case INIT_STATE: /*初始態*/{ #ifdef RTSP_DEBUGfprintf(stderr,"current method code is: %d \n",method); #endifswitch (method){case RTSP_ID_DESCRIBE: //狀態不變RTSP_describe(pRtspBuf);//printf("3\r\n");break;case RTSP_ID_SETUP: //狀態變為就緒態//printf("4\r\n");if (RTSP_setup(pRtspBuf) == ERR_NOERROR){//printf("5\r\n");pRtspSess->cur_state = READY_STATE;fprintf(stderr,"TRANSFER TO READY STATE!\n");}break;case RTSP_ID_TEARDOWN: //狀態不變RTSP_teardown(pRtspBuf);break;case RTSP_ID_OPTIONS:if (RTSP_options(pRtspBuf) == ERR_NOERROR){pRtspSess->cur_state = INIT_STATE; //狀態不變}break;case RTSP_ID_PLAY: //method not valid this state.case RTSP_ID_PAUSE:send_reply(455, 0, pRtspBuf);break;default:send_reply(501, 0, pRtspBuf);break;}break;}case READY_STATE:{ #ifdef RTSP_DEBUGfprintf(stderr,"current method code is:%d\n",method); #endifswitch (method){case RTSP_ID_PLAY: //狀態遷移為播放態if (RTSP_play(pRtspBuf) == ERR_NOERROR){fprintf(stderr,"\tStart Playing!\n");pRtspSess->cur_state = PLAY_STATE;}break;case RTSP_ID_SETUP:if (RTSP_setup(pRtspBuf) == ERR_NOERROR) //狀態不變{pRtspSess->cur_state = READY_STATE;}break;case RTSP_ID_TEARDOWN:RTSP_teardown(pRtspBuf); //狀態變為初始態 ?break;case RTSP_ID_OPTIONS:if (RTSP_options(pRtspBuf) == ERR_NOERROR){pRtspSess->cur_state = INIT_STATE; //狀態不變}break;case RTSP_ID_PAUSE: // method not valid this state.send_reply(455, 0, pRtspBuf);break;case RTSP_ID_DESCRIBE:RTSP_describe(pRtspBuf);break;default:send_reply(501, 0, pRtspBuf);break;}break;}case PLAY_STATE:{switch (method){case RTSP_ID_PLAY:// Feature not supportedfprintf(stderr,"UNSUPPORTED: Play while playing.\n");send_reply(551, 0, pRtspBuf); // Option not supportedbreak; /* //不支持暫停命令case RTSP_ID_PAUSE: //狀態變為就緒態if (RTSP_pause(pRtspBuf) == ERR_NOERROR){pRtspSess->cur_state = READY_STATE;}break; */case RTSP_ID_TEARDOWN:RTSP_teardown(pRtspBuf); //狀態遷移為初始態break;case RTSP_ID_OPTIONS:break;case RTSP_ID_DESCRIBE:RTSP_describe(pRtspBuf);break;case RTSP_ID_SETUP:break;}break;}/* PLAY state */default:{/* invalid/unexpected current state. */fprintf(stderr,"%s State error: unknown state=%d, method code=%d\n", __FUNCTION__, pRtspSess->cur_state, method);}break;}/* end of current state switch */#ifdef RTSP_DEBUGprintf("leaving rtsp_state_machine!\n"); #endif

    以上就是處理rtsp交互的狀態機,結合上面列出的RTSP交互過程,describe和setup兩個方法將在初始態處理,當setup成功后,狀態變為就緒態,這個狀態下會給一些必要的屬性重新賦值,這些屬性是控制底層數據讀取的標志,之后變成PLAY態,這個狀態下會不斷從底層取數據處理并封裝發送到客戶端,一旦連接中斷,狀態又會變回初始態。下面我講一下各個方法的處理代碼。
    首先是Describe

    char object[255], trash[255];char *p;unsigned short port;char s8Url[255];char s8Descr[MAX_DESCR_LENGTH];char server[128];char s8Str[128];/*根據收到的請求請求消息,跳過方法名,分離出URL*/if (!sscanf(pRtsp->in_buffer, " %*s %254s ", s8Url))//%*s表示第一個匹配到的%s被過濾掉{fprintf(stderr, "Error %s,%i\n", __FILE__, __LINE__);send_reply(400, 0, pRtsp); /* bad request */printf("get URL error");return ERR_NOERROR;}/*驗證URL */switch (ParseUrl(s8Url, server, &port, object, sizeof(object))){case 1: /*請求錯誤*/fprintf(stderr, "Error %s,%i\n", __FILE__, __LINE__);send_reply(400, 0, pRtsp);printf("url request error");return ERR_NOERROR;break;case -1: /*內部錯誤*/fprintf(stderr,"url error while parsing !\n");send_reply(500, 0, pRtsp);printf("inner error");return ERR_NOERROR;break;default:break;}/*取得序列號,并且必須有這個選項*/if ((p = strstr(pRtsp->in_buffer, HDR_CSEQ)) == NULL){fprintf(stderr, "Error %s,%i\n", __FILE__, __LINE__);send_reply(400, 0, pRtsp); /* Bad Request */printf("get serial num error");return ERR_NOERROR;}else{if (sscanf(p, "%254s %d", trash, &(pRtsp->rtsp_cseq)) != 2){fprintf(stderr, "Error %s,%i\n", __FILE__, __LINE__);send_reply(400, 0, pRtsp); /*請求錯誤*/printf("get serial num 2 error");return ERR_NOERROR;}}//獲取SDP內容GetSdpDescr(pRtsp, s8Descr, s8Str);//發送Describe響應//printf("----------------1\r\n");SendDescribeReply(pRtsp, object, s8Descr, s8Str);//printf("2\r\n");return ERR_NOERROR;

    這里說一下一些常用的字段處理函數:
    ①strstr

    strstr(str1,str2)

    strstr()函數用于判斷字符串str2是否是str1的子串。如果是,則該函數返回str2在str1中首次出現的地址;否則,返回NULL。
    ② strncmp

    int strncmp ( const char * str1, const char * str2, size_t n );

    str1, str2 為需要比較的兩個字符串,n為要比較的字符的數目。若str1與str2的前n個字符相同,則返回0;若s1大于s2,則返回大于0的值;若s1 小于s2,則返回小于0的值。
    ③strchr

    char *strchr(const char *s,char c)

    查找字符串s中首次出現字符c的位置。
    ④strncpy

    char*strncpy(char *dest, const char *src, int n)

    把src所指向的字符串中以src地址開始的前n個字節復制到dest所指的數組中,并返回被復制后的dest
    ⑤strcpy

    char *strcpy(char* dest, const char *src);

    把從src地址開始且含有NULL結束符(’\0’)的字符串復制到以dest開始的地址空間,src和dest所指內存區域不可以重疊且dest必須有足夠的空間來容納src的字符串。
    ⑥strcat

    char *strcat(char *dest, const char *src);

    把src所指向的字符串(包括“\0”)復制到dest所指向的字符串后面(刪除dest原來末尾的“\0”)。要保證dest足夠長,以容納被復制進來的*src。*src中原有的字符不變。返回指向dest的指針。

    通過以上這些字段處理函數提取RTSP信報中想要的信息,并在GetSdpDescr(pRtsp, s8Descr, s8Str);這個函數中組建自己的SDP。這里貼一下組的SDP:

    struct ifreq stIfr;//linux 網絡接口用來配置ip地址,激活接口,配置MTUchar pSdpId[128];//char rtp_port[5];strcpy(stIfr.ifr_name, "br0");if(ioctl(pRtsp->fd, SIOCGIFADDR, &stIfr) < 0){//printf("Failed to get host eth0 ip\n");strcpy(stIfr.ifr_name, "eth0");if(ioctl(pRtsp->fd, SIOCGIFADDR, &stIfr) < 0){printf("Failed to get host br0 or eth0 ip\n");}}sock_ntop_host(&stIfr.ifr_addr, sizeof(struct sockaddr), s8Str, 128);GetSdpId(pSdpId);strcpy(pDescr, "v=0\r\n"); strcat(pDescr, "o=-");strcat(pDescr, pSdpId);strcat(pDescr," ");strcat(pDescr, pSdpId);strcat(pDescr," IN IP4 ");strcat(pDescr, s8Str);strcat(pDescr, "\r\n");strcat(pDescr, "s=H.264 Video, streamed by the Test Media Server\r\n");//(session name)strcat(pDescr, "i=test.h264\r\n");//session的信息strcat(pDescr, "t=0 0\r\n");//時間信息,分別表示開始的時間和結束的時間,一般在流媒體的直播的時移中見的比較多strcat(pDescr, "a=tool:Test Streaming Media v2018.11.30\r\n");//創建任務描述的工具的名稱及版本號 strcat(pDescr, "a=type:broadcast\r\n");//會議類型strcat(pDescr, "a=control:*\r\n");strcat(pDescr, "m=video 0 RTP/AVP 96\r\n");strcat(pDescr, "\r\n"); strcat(pDescr,"b=AS:500\r\n");/**** Dynamically defined payload ****/strcat(pDescr,"a=rtpmap:96");strcat(pDescr," "); strcat(pDescr,"H264/90000");strcat(pDescr, "\r\n");strcat(pDescr,"a=fmtp:96 packetization-mode=1;");strcat(pDescr,"profile-level-id=");strcat(pDescr,psp.base64profileid);strcat(pDescr,";sprop-parameter-sets=");strcat(pDescr,psp.base64sps);strcat(pDescr,",");strcat(pDescr,psp.base64pps);strcat(pDescr, "\r\n");strcat(pDescr,"a=control:track1");strcat(pDescr, "\r\n");printf("\n\n%s,%d===>psp.base64profileid=%s,psp.base64sps=%s,psp.base64pps=%s\n\n",__FUNCTION__,__LINE__,psp.base64profileid,psp.base64sps,psp.base64pps);

    關于SDP協議我這里不寫太多

    https://blog.csdn.net/jobbofhe/article/details/78477407

    這篇博文寫得挺全了我覺得,想了解多一點的可以在上面的網址看看。這里注意一下,sprop-parameter-sets=后面跟的是Base64編碼后的SPS和PPS。組好SDP之后發送出去

    char *pMsgBuf; /* 用于獲取響應緩沖指針*/int s32MbLen;/* 分配空間,處理內部錯誤*/s32MbLen = 2048;pMsgBuf = (char *)malloc(s32MbLen);if (!pMsgBuf){fprintf(stderr,"send_describe_reply(): unable to allocate memory\n");send_reply(500, 0, rtsp); /* internal server error */if (pMsgBuf){free(pMsgBuf);}return ERR_ALLOC;}/*構造describe消息串*/sprintf(pMsgBuf, "%s %d %s"RTSP_EL"CSeq: %d"RTSP_EL"Server: %s/%s"RTSP_EL, RTSP_VER, 200, get_stat(200), rtsp->rtsp_cseq, PACKAGE, VERSION);add_time_stamp(pMsgBuf, 0); /*添加時間戳*/strcat(pMsgBuf, "Content-Type: application/sdp"RTSP_EL); /*實體頭,表示實體類型*//*用于解析實體內相對url的 絕對url*/sprintf(pMsgBuf + strlen(pMsgBuf), "Content-Base: rtsp://%s/%s/"RTSP_EL, s8Str, object);sprintf(pMsgBuf + strlen(pMsgBuf), "Content-Length: %d"RTSP_EL, strlen(descr)); /*消息體的長度*/strcat(pMsgBuf, RTSP_EL);/*消息頭結束*//*加上消息體*/strcat(pMsgBuf, descr); /*describe消息*//*向緩沖區中填充數據*/bwrite(pMsgBuf, (unsigned short) strlen(pMsgBuf), rtsp);free(pMsgBuf);return ERR_NOERROR;

    Describe 之后是SetUp

    char s8TranStr[128], *s8Str;char *pStr;RTP_transport Transport;int s32SessionID=0;RTP_session *rtp_s, *rtp_s_prec;RTSP_session *rtsp_s;if ((s8Str = strstr(pRtsp->in_buffer, HDR_TRANSPORT)) == NULL){fprintf(stderr, "Error %s,%i\n", __FILE__, __LINE__);send_reply(406, 0, pRtsp); // Not Acceptableprintf("not acceptable");return ERR_NOERROR;}//檢查傳輸層子串是否正確if (sscanf(s8Str, "%*10s %255s", s8TranStr) != 1){fprintf(stderr,"SETUP request malformed: Transport string is empty\n");send_reply(400, 0, pRtsp); // Bad Requestprintf("check transport 400 bad request");return ERR_NOERROR;}fprintf(stderr,"*** transport: %s ***\n", s8TranStr);//如果需要增加一個會話if ( !pRtsp->session_list ){pRtsp->session_list = (RTSP_session *) calloc(1, sizeof(RTSP_session));}rtsp_s = pRtsp->session_list;//建立一個新會話,插入到鏈表中if (pRtsp->session_list->rtp_session == NULL){pRtsp->session_list->rtp_session = (RTP_session *) calloc(1, sizeof(RTP_session));rtp_s = pRtsp->session_list->rtp_session;}else{for (rtp_s = rtsp_s->rtp_session; rtp_s != NULL; rtp_s = rtp_s->next){rtp_s_prec = rtp_s;}rtp_s_prec->next = (RTP_session *) calloc(1, sizeof(RTP_session));rtp_s = rtp_s_prec->next;}//起始狀態為暫停rtp_s->pause = 1;rtp_s->hndRtp = NULL;Transport.type = RTP_no_transport;if((pStr = strstr(s8TranStr, RTSP_RTP_AVP))){//Transport: RTP/AVPpStr += strlen(RTSP_RTP_AVP);if ( !*pStr || (*pStr == ';') || (*pStr == ' ')){//單播if (strstr(s8TranStr, "unicast")){//如果指定了客戶端端口號,填充對應的兩個端口號if( (pStr = strstr(s8TranStr, "client_port")) ){pStr = strstr(s8TranStr, "=");sscanf(pStr + 1, "%d", &(Transport.u.udp.cli_ports.RTP));pStr = strstr(s8TranStr, "-");sscanf(pStr + 1, "%d", &(Transport.u.udp.cli_ports.RTCP));}//服務器端口if (RTP_get_port_pair(&Transport.u.udp.ser_ports) != ERR_NOERROR){fprintf(stderr, "Error %s,%d\n", __FILE__, __LINE__);send_reply(500, 0, pRtsp);/* Internal server error */return ERR_GENERIC;}//建立RTP套接字rtp_s->hndRtp = (struct _tagStRtpHandle*)RtpCreate((unsigned int)(((struct sockaddr_in *)(&pRtsp->stClientAddr))->sin_addr.s_addr), Transport.u.udp.cli_ports.RTP, _h264nalu);printf("<><><><>Creat RTP<><><><>\n");Transport.u.udp.is_multicast = 0;}else{printf("multicast not codeing\n");//multicast 多播處理....}Transport.type = RTP_rtp_avp;}else if (!strncmp(s8TranStr, "/TCP", 4)){if( (pStr = strstr(s8TranStr, "interleaved")) ){pStr = strstr(s8TranStr, "=");sscanf(pStr + 1, "%d", &(Transport.u.tcp.interleaved.RTP));if ((pStr = strstr(pStr, "-")))sscanf(pStr + 1, "%d", &(Transport.u.tcp.interleaved.RTCP));elseTransport.u.tcp.interleaved.RTCP = Transport.u.tcp.interleaved.RTP + 1;}else{}Transport.rtp_fd = pRtsp->fd; // Transport.rtcp_fd_out = pRtsp->fd; // Transport.rtcp_fd_in = -1;}}printf("pstr=%s\n",pStr);if (Transport.type == RTP_no_transport){fprintf(stderr,"AAAAAAAAAAA Unsupported Transport,%s,%d\n", __FILE__, __LINE__);send_reply(461, 0, pRtsp);// Bad Requestreturn ERR_NOERROR;}memcpy(&rtp_s->transport, &Transport, sizeof(Transport));//如果有會話頭,就有了一個控制集合if ((pStr = strstr(pRtsp->in_buffer, HDR_SESSION)) != NULL){if (sscanf(pStr, "%*s %d", &s32SessionID) != 1){fprintf(stderr, "Error %s,%i\n", __FILE__, __LINE__);send_reply(454, 0, pRtsp); // Session Not Foundreturn ERR_NOERROR;}}else{//產生一個非0的隨機的會話序號struct timeval stNowTmp;gettimeofday(&stNowTmp, 0);srand((stNowTmp.tv_sec * 1000) + (stNowTmp.tv_usec / 1000));s32SessionID = 1 + (int) (10.0 * rand() / (100000 + 1.0));if (s32SessionID == 0){s32SessionID++;}}pRtsp->session_list->session_id = s32SessionID;pRtsp->session_list->rtp_session->sched_id = schedule_add(rtp_s);send_setup_reply(pRtsp, rtsp_s, rtp_s);return ERR_NOERROR;

    這里重點講一下兩地方吧,一個是RtpCreate()函數

    HndRtp hRtp = NULL;struct timeval stTimeval;struct ifreq stIfr;int s32Broadcast = 1;struct sockaddr_in addr;hRtp = (HndRtp)calloc(1, sizeof(StRtpObj));if(NULL == hRtp){printf("Failed to create RTP handle\n");goto cleanup;}hRtp->s32Sock = -1;if((hRtp->s32Sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0){printf("Failed to create socket\n");goto cleanup;}if(0xFF000000 == (u32IP & 0xFF000000)){if(-1 == setsockopt(hRtp->s32Sock, SOL_SOCKET, SO_BROADCAST, (char *)&s32Broadcast, sizeof(s32Broadcast))){printf("Failed to set socket\n");goto cleanup;}}memset(&addr, 0, sizeof(addr));while(1){addr.sin_port = BigLittleSwap16(server_port);addr.sin_family = AF_INET;addr.sin_addr.s_addr = INADDR_ANY;hRtp->stServAddr.sin_family = AF_INET;hRtp->stServAddr.sin_port = BigLittleSwap16(s32Port);hRtp->stServAddr.sin_addr.s_addr = u32IP;bzero(&(hRtp->stServAddr.sin_zero), 8);if (bind(hRtp->s32Sock, (struct sockaddr *)&addr, sizeof(addr))){printf("can't bind !!!!!!!!!!!!!!!!!!!!!!!!!!!");server_port++;}elsebreak;}//初始化序號hRtp->u16SeqNum = 0;//初始化時間戳hRtp->u32TimeStampInc = 0;hRtp->u32TimeStampCurr = 0;//獲取當前時間if(gettimeofday(&stTimeval, NULL) == -1){printf("Failed to get os time\n");goto cleanup;}hRtp->u32PrevTime = stTimeval.tv_sec * 1000 + stTimeval.tv_usec / 1000;hRtp->emPayload = emPayload;//獲取本機網絡設備名strcpy(stIfr.ifr_name, "br0");if(ioctl(hRtp->s32Sock, SIOCGIFADDR, &stIfr) < 0){//printf("Failed to get host ip\n");strcpy(stIfr.ifr_name, "eth0");if(ioctl(hRtp->s32Sock, SIOCGIFADDR, &stIfr) < 0){printf("Failed to get host eth0 or wlan0 ip\n");goto cleanup;}}hRtp->u32SSrc = BigLittleSwap32(((struct sockaddr_in *)(&stIfr.ifr_addr))->sin_addr.s_addr);local_ip = hRtp->u32SSrc;//hRtp->u32SSrc = htonl(((struct sockaddr_in *)(&stIfr.ifr_addr))->sin_addr.s_addr);printf("!!!!!!!!!!!!!!!!!!!!!!rtp create:addr:%x,port:%d,local%x\n",u32IP,s32Port,hRtp->u32SSrc);printf("<><><><>success creat RTP<><><><>\n");return (unsigned int)hRtp; cleanup:if(hRtp){if(hRtp->s32Sock >= 0){close(hRtp->s32Sock);}free(hRtp);}

    這個函數主要是創建了一個用于RTP傳輸的Socket,用來傳輸封裝好的RTP數據包,這一部分我會在第三部分講。另一個要注意的地方就是在

    pRtsp->session_list->rtp_session->sched_id = schedule_add(rtp_s);

    schedule_add(rtp_s)這個函數里面給每一個連接的關鍵參數置位,這些參數是用來控制取底層數據并保存在緩沖區的判斷依據,還有就是設置了RtpSend()這個回調函數,這個回調函數會在Play階段被調用,用來封裝底層上來的碼流數據并發送。

    Play和Teardown比較簡單,我這邊就不放代碼了,PLay主要還是設置屬性,使進入讀取底層數據并保存的判定為真,Teardown主要是釋放一些內存,以及釋放RTSP鏈表的一些操作。

    總結一下吧,關于RTSP交互這一塊,首先就是建立一個Socket用以接受發送RTSP的數據報文的,通過這個Socket進行我上面介紹過的服務器和客戶端的交互,在Setup階段創建新的Socket連接用來做具體的碼流數據傳輸,Play階段就是不斷的取底層數據進行封裝發送,TearDown階段斷開連接并釋放相關的指針或鏈表。

    關于具體的碼流是怎么封裝的我會在第三部分講。

    總結

    以上是生活随笔為你收集整理的网络摄像头Rtsp直播方案(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    97av免费视频 | 日韩中文字幕a | 精品999久久久 | 成年人视频在线免费播放 | 99r在线视频 | 国产中文字幕第一页 | 国产精品人人做人人爽人人添 | 日韩国产精品久久 | 中文字幕乱码在线播放 | 国产精品完整版 | 免费男女羞羞的视频网站中文字幕 | 中文日韩在线 | 伊人午夜 | 久久亚洲影院 | 少妇av片 | 久久人人爽人人爽人人片av软件 | 久久99精品久久只有精品 | 国产精品女主播一区二区三区 | 日韩激情视频在线 | 麻豆视屏 | 91爱爱电影 | 国产三级香港三韩国三级 | 成人黄色av免费在线观看 | 久久这里只有精品久久 | 国产成人精品在线 | 人人草在线观看 | 国产无区一区二区三麻豆 | 久久久久久久久电影 | 国产1级毛片 | 日韩三级中文字幕 | 黄a网站 | 伊人五月天 | 久草视频中文在线 | 久久影视精品 | 成人性生活大片 | 国产视频精品久久 | 精品久久1 | 久久久久久久久久久黄色 | 午夜视频99 | 久久最新视频 | www色婷婷com| 亚洲丝袜中文 | 香蕉精品在线观看 | www.天天成人国产电影 | 97电影网手机版 | 日韩欧美成| 在线免费观看成人 | 久久久私人影院 | 久久久久久久久久久影院 | 午夜.dj高清免费观看视频 | 米奇狠狠狠888 | 久久精品综合视频 | 欧美日韩中文字幕视频 | 久久久精品国产一区二区三区 | 亚洲视频999 | 91av观看 | 91完整视频| 国产分类视频 | 在线观看视频 | 狠狠的日日 | 亚洲精品456在线播放第一页 | 亚洲三级在线 | 91精品国产成人观看 | 人人爽人人爽人人片av | 五月婷香 | 午夜精品一二三区 | 中文字幕在线观看一区 | 99av在线视频 | 日韩在线视频线视频免费网站 | 91视频国产免费 | 精品一二三区视频 | 久久精品国产美女 | 色综合久久五月 | 天天草综合网 | 色福利网 | 国产a视频免费观看 | 国精产品999国精产品岳 | 欧美不卡视频在线 | 一区二区精品在线观看 | 日韩精品视频免费 | 在线观看mv的中文字幕网站 | 日韩毛片在线一区二区毛片 | 国产伦精品一区二区三区免费 | 东方av在 | 国产91全国探花系列在线播放 | 三级av中文字幕 | 久久99在线| 亚洲三级黄| 麻豆影视在线播放 | 91视频在线免费下载 | 天天亚洲综合 | 久草视频手机在线 | 在线观看网站av | 黄色国产高清 | 97网站| 91一区一区三区 | 亚洲成人软件 | 国产视频久久久久 | 国产一级视屏 | aaa毛片视频 | 国产成人一区在线 | 国产一区视频在线播放 | 奇米影视8888在线观看大全免费 | 天天夜夜亚洲 | 午夜精品中文字幕 | 999久久久免费精品国产 | 香蕉97视频观看在线观看 | 超碰人人在| 极品美女被弄高潮视频网站 | 美女福利视频 | 亚洲第一区在线播放 | 91在线播放国产 | 免费看的黄色录像 | 免费日韩av片 | 黄色1级毛片 | 亚洲精品美女久久久 | 夜色.com| 久久成人综合视频 | 日日摸日日 | 精品久久一二三区 | 国产精品福利小视频 | 久久99精品波多结衣一区 | 免费看黄的 | 精品视频成人 | 91成年人视频 | 婷婷在线色| 国产小视频在线免费观看视频 | 日韩在线一区二区免费 | 国产日韩一区在线 | 国产一区二区在线观看视频 | 在线中文字母电影观看 | 国产伦理一区二区 | 外国av网 | 4hu视频| 成人av影视| 日本精品久久久久影院 | 超碰97人人射妻 | 人人狠 | 欧美做受高潮1 | 国产精品岛国久久久久久久久红粉 | 成人av手机在线 | 国产99一区 | 伊人天天狠天天添日日拍 | 在线一级片 | 国产在线看 | 日韩在线观看视频一区二区三区 | 不卡国产在线 | 欧美成人精品欧美一级乱黄 | 黄色网中文字幕 | 88av网站| 亚洲国产精品va在线看黑人动漫 | 五月激情综合婷婷 | 精品成人在线 | 一级一片免费视频 | 精品免费观看视频 | 伊人天堂久久 | av在线免费播放 | 欧美日韩精品影院 | 一区二区三区韩国免费中文网站 | 九九九九色 | 麻豆视频国产精品 | 天天草天天色 | 九精品 | 在线视频观看成人 | 玖玖视频免费在线 | 欧美a级成人淫片免费看 | 区一区二在线 | 射九九 | 久久久久综合视频 | 97国产情侣爱久久免费观看 | 超碰在线亚洲 | 国产一级不卡视频 | 国产区精品区 | 亚洲国产丝袜在线观看 | av黄色在线观看 | 欧美一区二区三区特黄 | 日韩免费播放 | 91夫妻自拍 | 9色在线视频| 日韩在线精品 | 欧美一级免费在线 | 在线播放一区二区三区 | 国产一级视频在线免费观看 | 欧美成天堂网地址 | 久久久www成人免费精品 | 日韩中文字幕在线观看 | 操老逼免费视频 | 欧美一区二区在线免费看 | 国产精品乱码一区二三区 | 久久久久久毛片 | av千婊在线免费观看 | 九九热免费在线观看 | 国产一区二区在线影院 | 国产麻豆视频在线观看 | 国产在线观看一区 | 久久久久久久99 | 97伊人网| 中文字幕久久精品亚洲乱码 | 国产精品精品视频 | 91av在线免费看 | 久久久在线 | 91污污视频在线观看 | 亚洲人xxx | 在线观看一区 | 日韩视频在线不卡 | 玖玖在线免费视频 | 久久99国产精品自在自在app | 国产乱对白刺激视频不卡 | 不卡的av在线播放 | 精品一区 在线 | 国产成人精品一区二 | 精品999在线 | 久久中文字幕视频 | 久久不射电影院 | avove黑丝 | 国产午夜精品一区二区三区四区 | 国产精品久久久久一区 | 久草在线视频看看 | 国产精品一二三 | 国产精品1区 | 国产午夜视频在线观看 | 国产中文| 色综合久久久久综合体桃花网 | 在线国产高清 | 国产亚洲精品久久 | 国产首页 | www.av免费观看 | 高清国产午夜精品久久久久久 | 国产又黄又猛又粗 | 97电影手机 | 成人毛片在线观看视频 | 久久精彩| 黄色成品视频 | 欧美久久久 | 久久精品首页 | 超碰97人人干 | 亚洲精品视频在线观看免费视频 | 国产一区二区免费在线观看 | 成人动图 | 亚洲爱av | 中文字幕乱码日本亚洲一区二区 | 亚洲伦理一区二区 | 91在线观看视频 | 国产精品免费一区二区 | 丁香婷婷激情五月 | 黄视频网站大全 | 亚洲免费在线观看视频 | 免费看的黄色的网站 | 日韩三级视频在线观看 | 婷婷激情av | 成年人电影毛片 | 日韩成人邪恶影片 | 国产精品一区免费看8c0m | 欧美最猛性xxxx | 综合铜03| 色综合久久久久久久久五月 | 国内精品在线看 | 日韩中文字幕视频在线 | 九九九九九九精品任你躁 | 五月天天天操 | 久久国产片 | 国产精品自产拍在线观看 | 国产在线高清视频 | 亚洲在线免费视频 | 国产精品日韩欧美一区二区 | www久草| 久久99精品一区二区三区三区 | 亚洲一区日韩在线 | 在线视频 一区二区 | 人人干网 | 久久午夜视频 | 国产成人福利在线观看 | 中文字幕一区二区三区乱码不卡 | 久影院 | 在线免费国产视频 | 97精产国品一二三产区在线 | 日韩在线高清 | 国产精品乱码高清在线看 | 国产成人精品一区二区三区福利 | 日韩a级黄色片 | 婷婷日日 | 欧美日韩a视频 | 天天操天天干天天干 | 欧美最猛性xxx | 在线 国产一区 | 日日夜夜精品免费视频 | www.xxx.性狂虐| 色五婷婷 | 狠狠狠综合| 久久综合操 | 色欧美视频 | 在线观看香蕉视频 | 久久久久久久久免费 | 三级毛片视频 | 久久久久久黄色 | 午夜视频一区二区三区 | 欧美va日韩va | 操久久免费视频 | 亚洲专区视频在线观看 | www.夜夜爱 | 久久精品国产一区二区电影 | 五月婷婷久久丁香 | 国产精久久久久久妇女av | 天天爱天天操 | 狠狠干天天 | 色婷婷97| 99在线播放 | 在线观看小视频 | 久久久麻豆视频 | 色综合天天狠天天透天天伊人 | 中文字幕色婷婷在线视频 | 亚洲精品乱码久久久久久蜜桃动漫 | 伊人五月婷 | a级片在线播放 | 婷婷综合久久 | 最近乱久中文字幕 | 亚洲色图激情文学 | 天天综合成人 | 五月天视频网 | av在线小说 | 国产黄色一级片 | 久久久久久久久久网 | 国产精品久久一区二区三区不卡 | 不卡精品 | 九九热.com | 黄色毛片网站在线观看 | 亚洲成av片人久久久 | 一区 二区电影免费在线观看 | 国产日韩欧美在线观看视频 | 亚洲经典视频在线观看 | 亚洲美女免费精品视频在线观看 | 国产日韩精品一区二区 | 色在线高清| 草久在线视频 | 国产va精品免费观看 | 午夜精品久久久久久久久久久久 | 精品国产一区二区三区男人吃奶 | 国产激情久久久 | 伊甸园永久入口www 99热 精品在线 | 中文在线字幕免 | 国产黄在线免费观看 | 成人网色 | 成年人免费观看国产 | 99久久99久久免费精品蜜臀 | 色视频在线免费 | 麻豆传媒视频在线播放 | 午夜视频二区 | 久久久久久久久久久精 | 国产精品午夜免费福利视频 | 国产污视频在线观看 | 一区二区三区在线免费观看视频 | 狠狠狠色丁香婷婷综合久久五月 | 久久99精品热在线观看 | .精品久久久麻豆国产精品 亚洲va欧美 | 天天天天天天天操 | 久久久精品 一区二区三区 国产99视频在线观看 | 国产精品久久久久久久久久妇女 | 亚洲伦理一区二区 | 激情综合国产 | 亚洲精品在线观看不卡 | 色 免费观看 | 国产精品毛片一区二区 | 在线观看视频一区二区 | 最近2019年日本中文免费字幕 | 91九色蝌蚪视频 | 久久久穴| av黄色大片 | 日韩精品一区二区三区三炮视频 | 国产在线播放一区 | 又黄又爽的视频在线观看网站 | 国产高清一区二区 | 国产成人黄色在线 | 高清av免费看 | 18国产精品白浆在线观看免费 | 日韩精品一区二区在线视频 | 中文字幕 国产视频 | 久久精品日本啪啪涩涩 | 17videosex性欧美 | 视频国产在线 | 日本少妇视频 | 日韩一区视频在线 | 中文字幕免费观看视频 | 国产精品视频app | 人人爽久久久噜噜噜电影 | av免费在线免费观看 | 国产精品久久久久久久久岛 | 免费激情在线电影 | 一区二区三区在线视频观看58 | 国内久久久久久 | av在线免费播放网站 | 四虎国产精品免费 | 亚洲免费精品一区二区 | 欧美日韩另类在线观看 | 香蕉免费| 91成人免费在线 | 国产精品久久久久久一区二区 | 91久久久久久国产精品 | 国产 一区二区三区 在线 | 少妇自拍av | 黄色精品国产 | 少妇18xxxx性xxxx片| 久久一区二区免费视频 | 国产一级特黄毛片在线毛片 | 视频在线观看入口黄最新永久免费国产 | 中文字幕你懂的 | 黄色特级一级片 | 国产精品久久久精品 | 日本中文字幕网址 | 日韩黄色大片在线观看 | 日韩69av| 中文字幕国产一区二区 | 午夜视频在线网站 | av黄色成人| 久久艹人人 | 天天操天天干天天摸 | 日韩成人免费观看 | 999国产精品视频 | 欧美成人区 | 国产蜜臀av| 天天爱天天射 | 99视频在线观看免费 | 久久精品中文字幕一区二区三区 | 国产99一区| 在线看欧美 | 99久热在线精品 | 麻豆国产网站入口 | av电影一区二区三区 | 精品视频亚洲 | 国产91粉嫩白浆在线观看 | 三级视频国产 | 九九热精品视频在线观看 | 在线影视 一区 二区 三区 | 992tv又爽又黄的免费视频 | 国产网红在线观看 | 三级在线视频观看 | 日韩电影在线观看一区二区 | 91亚洲欧美激情 | 国产精品久久久久久久久久久久久久 | 免费看黄网站在线 | 蜜桃av久久久亚洲精品 | 国产主播大尺度精品福利免费 | 久久一级电影 | 精品国产一区二区三区四区vr | 中文字幕在线影视资源 | 久久免费的精品国产v∧ | 久久精品一二区 | 亚洲国产精品一区二区久久,亚洲午夜 | 成人av网站在线观看 | 最近中文字幕mv免费高清在线 | 国产99久久精品一区二区300 | 久久国产网| 久久色视频 | 天天曰夜夜操 | 亚洲一区二区麻豆 | 久草视频在线资源 | 美女精品 | 久久久高清视频 | 色综合天天射 | 日韩av在线免费播放 | japanesefreesex中国少妇 | 97夜夜澡人人双人人人喊 | 综合激情av | 日本性生活一级片 | www黄色av| 久久天堂亚洲 | 精品一区二区久久久久久久网站 | 国产最新视频在线 | 国产精品久久久久国产精品日日 | 国产精品久久久久久久久软件 | 丁香激情五月婷婷 | 一区中文字幕 | av免费看网站 | 国产欧美在线一区二区三区 | 欧美另类激情 | 99精品视频免费观看 | 国产午夜三级一区二区三桃花影视 | 免费看的毛片 | 国产成人精品一区二区在线观看 | 国产成人资源 | 一区二区三区免费在线观看视频 | 免费毛片一区二区三区久久久 | 久久综合色天天久久综合图片 | 国产亚洲欧美一区 | 亚洲最新av| 亚洲成年人在线播放 | 正在播放日韩 | 视频国产在线观看18 | 日韩精品专区在线影院重磅 | 国产黄色大片免费看 | 最新国产一区二区三区 | 欧美日韩国产精品一区二区 | 国产一区二区在线免费播放 | 亚洲伦理一区二区 | 99久久99久久| 久久久久二区 | 亚洲aⅴ免费在线观看 | www91在线观看 | 日日色综合 | 99久久精品免费看国产一区二区三区 | 午夜精品久久久久久久久久久久久久 | 精品不卡视频 | 日韩在线观看小视频 | 亚洲精品白浆高清久久久久久 | 在线观看国产一区二区 | 在线观看中文字幕一区二区 | 在线亚洲人成电影网站色www | 最新国产福利 | 精品视频国产一区 | 一区二区三区在线观看免费视频 | 成人v| 久久国色夜色精品国产 | 国产综合小视频 | 中文字幕中文字幕在线中文字幕三区 | 久久久久一区二区三区 | 久久天天操 | av天天在线观看 | 亚洲精品99久久久久久 | 久久久受www免费人成 | 免费在线观看av不卡 | 成人av影视观看 | 欧美一级在线观看视频 | 91视频啪| 久久热首页 | 日本少妇高清做爰视频 | 男女激情网址 | 日本丶国产丶欧美色综合 | 中日韩三级视频 | 午夜婷婷综合 | 国产精品毛片一区视频播不卡 | 综合久久精品 | 国模一二三区 | 久久免费视频7 | 国产视频在线观看免费 | 日本99久久 | a视频在线观看免费 | 久久激情视频 久久 | 中文字幕一区二区三区在线播放 | 精品国产一二三 | 97超碰中文字幕 | 手机看片久久 | 激情丁香综合五月 | 色婷婷播放 | 中文资源在线观看 | 一区二区三区四区五区在线视频 | av在线影片 | 天天操天天操天天干 | 99久久精品国产一区二区成人 | 欧美另类美少妇69xxxx | 免费91麻豆精品国产自产在线观看 | 人人爱人人爽 | 国产九九精品视频 | 麻豆视频在线播放 | 综合网成人 | 久久99精品国产麻豆婷婷 | 免费看毛片网站 | av综合网址 | 99视频精品| 精品久久国产精品 | 人人爽人人爽人人爽学生一级 | h视频在线看 | 美女网站色免费 | 丁香六月综合网 | 久在线观看 | 国产999视频在线观看 | 亚洲精品小视频 | 水蜜桃亚洲一二三四在线 | 2023天天干| 色.www| 日韩黄色免费电影 | 久久伊人热 | 国产精品成人品 | av电影在线观看完整版一区二区 | 黄色亚洲 | 午夜国产福利在线观看 | 久草在线这里只有精品 | 午夜美女福利直播 | 亚洲精品欧美视频 | 国产精品99久久99久久久二8 | 久久精品免费看 | 亚洲精品视频中文字幕 | 一区二区中文字幕在线观看 | 在线视频 国产 日韩 | 91成人精品一区在线播放69 | 免费99视频 | 五月婷婷六月丁香 | 伊人黄| 久久99精品国产99久久6尤 | 日本性生活免费看 | 日本婷婷色 | 免费av网址在线观看 | 日韩激情三级 | 美女av免费 | 国语精品免费视频 | 日韩电影中文,亚洲精品乱码 | 欧美激情h| 色噜噜狠狠色综合中国 | 婷婷色综合色 | 免费情趣视频 | 国产一区二区成人 | 国产精品久久久久免费观看 | 久草视频在线资源 | 97成人在线观看视频 | 亚洲日本国产精品 | 人人玩人人爽 | 国产一级高清视频 | 久久九九影院 | 国产精品6 | 久久免费看av | 最近中文字幕免费 | 在线观看免费一区 | 亚洲精品1区2区3区 超碰成人网 | aaa免费毛片| 日韩免费中文字幕 | 91亚洲欧美| 国产日韩在线观看一区 | 日本不卡一区二区 | 一级片视频在线 | 日b视频国产 | 精品一区二区在线免费观看 | 日本黄色免费在线观看 | 国产精品乱看 | 97久久精品午夜一区二区 | 精品一区二区三区香蕉蜜桃 | 国产精品不卡在线播放 | 人人澡av | 狠狠干激情 | 91自拍91| 麻豆91视频 | 操操操com| 欧美少妇影院 | 成人小视频在线观看免费 | 日韩久久电影 | 在线中文字幕播放 | 国产精品麻豆99久久久久久 | 伊人久久精品久久亚洲一区 | 久久99久久99 | 在线www色 | 久久精品福利视频 | 在线播放一区二区三区 | 91av影视| 超碰97公开 | 亚洲五月综合 | 精品爱爱| av日韩在线网站 | 亚洲精品婷婷 | 国产精品欧美精品 | 久久亚洲福利 | 天堂成人在线 | a久久免费视频 | 日韩欧美一区二区三区视频 | 亚洲天天在线 | 亚洲一区在线看 | 国产精品毛片一区二区 | 午夜视频在线观看网站 | 亚洲人成在线电影 | 国产h在线观看 | ,午夜性刺激免费看视频 | 中文字幕av在线电影 | 国产高清久久久久 | 91高清完整版在线观看 | 国产精品成人免费一区久久羞羞 | 日韩有码第一页 | 色网址99 | 超碰国产人人 | 欧美粗又大 | 日韩极品视频在线观看 | a v在线观看 | 91精品国产自产老师啪 | av手机在线播放 | 欧美日本日韩aⅴ在线视频 插插插色综合 | 超碰成人免费电影 | 国产精品一区二区三区在线 | 天天激情| 亚洲 中文 欧美 日韩vr 在线 | 国产特级毛片aaaaaa高清 | 三三级黄色片之日韩 | 在线一二区 | a天堂一码二码专区 | 国产精品第三页 | 色综合天天视频在线观看 | 日韩在线一二三区 | 黄色免费国产 | 国产精品h在线观看 | 日韩电影中文字幕在线观看 | 在线a亚洲视频播放在线观看 | 有没有在线观看av | 免费a v网站 | 久久99亚洲网美利坚合众国 | 成人黄色电影免费观看 | 免费视频99 | 91麻豆操 | 色国产精品一区在线观看 | 久久激情视频 | 精品国产自在精品国产精野外直播 | 国产精品伦一区二区三区视频 | 免费在线观看视频a | 中文字幕婷婷 | 亚洲欧美日本A∨在线观看 青青河边草观看完整版高清 | 四虎在线免费观看视频 | 亚洲黄色成人网 | 麻豆国产精品视频 | www.狠狠插.com | 免费视频在线观看网站 | 亚洲一区天堂 | 色婷婷激婷婷情综天天 | 一区二区视 | 免费久久99精品国产婷婷六月 | 欧美电影在线观看 | 99精品黄色 | 久久久久久久久久久免费视频 | 免费在线观看黄网站 | 五月综合网| 九色91在线视频 | 男女全黄一级一级高潮免费看 | 中文字幕一二 | 国产97视频 | 国内99视频| 日韩天天操 | 亚洲精品乱码久久久久久高潮 | 91香蕉国产在线观看软件 | 狠狠干美女 | 国产视频精品在线 | 亚洲一本视频 | 久久中文欧美 | 欧美成人xxxxxxxx| 友田真希x88av | 成人97视频 | 草久视频在线观看 | 亚洲欧美一区二区三区孕妇写真 | 国产成人精品一区二区 | 久久精品一二三区 | 在线观看的黄色 | 欧美伦理一区 | 91亚色视频| 国产精品成人a免费观看 | 国产一区视频在线观看免费 | 久久综合毛片 | 在线观看中文字幕第一页 | 国产视频精品在线 | 中文字幕免费观看全部电影 | 在线精品播放 | 日日爽| av看片网址| 免费无遮挡动漫网站 | www.色就是色 | 色国产精品 | 992tv人人草 黄色国产区 | 欧美日韩不卡一区二区 | 在线观看av片 | 精品国产免费一区二区三区五区 | 日本公妇在线观看 | 国产精品3 | 中文字幕在线观看第二页 | 亚洲电影第一页av | 在线观看中文字幕亚洲 | 蜜臀av麻豆| 99这里只有久久精品视频 | 激情综合五月婷婷 | 色全色在线资源网 | 国产精品av在线免费观看 | 国产高清视频在线观看 | 天堂黄色片 | 久久伊人爱 | 在线免费中文字幕 | 午夜精品一区二区三区在线观看 | 国产一级电影 | 日韩精品一区二区三区免费观看视频 | 国产精品久久久久999 | 免费观看一级一片 | 精品毛片久久久久久 | 中文一区在线 | 久久国产精品成人免费浪潮 | 欧美激情精品 | 美女免费视频黄 | 91亚洲精品乱码久久久久久蜜桃 | 少妇搡bbbb搡bbb搡69 | 91免费高清在线观看 | 欧美日韩不卡在线视频 | 久久天天躁夜夜躁狠狠85麻豆 | 亚洲免费婷婷 | 中文字幕在线观看日本 | 日韩91精品 | 久久免费在线观看 | 奇米网444 | 日韩91在线| 亚洲一级片免费观看 | 亚洲 在线 | 免费看国产视频 | 国产精品区一区 | 丁香五月亚洲综合在线 | 91香蕉视频好色先生 | 日日夜夜精品视频天天综合网 | 成人午夜片av在线看 | 黄污网| 国内精品中文字幕 | 亚洲爽爽网 | 精精国产xxxx视频在线播放 | 婷婷色中文网 | 久久最新 | 国产不卡免费 | 日韩a级黄色| av福利在线 | 久久久久久久久久久高潮一区二区 | 丁香花在线视频观看免费 | 久久精品在线 | 欧美福利片在线观看 | 97人人爽| 美女久久久久久久久久 | 免费观看性生活大片3 | 中文字幕在线有码 | 久久久久久国产精品999 | 美女国产网站 | 国产精品久久久久久久久久 | 久久免费电影 | 日韩av高清在线观看 | 高清av免费一区中文字幕 | 精品免费一区 | 久久精品国产精品亚洲 | 91视频免费网站 | 国产精品v欧美精品 | 中文字幕观看在线 | 久久视频国产 | www.91av在线 | 亚洲精品国产精品国自产观看浪潮 | 草久久久 | 亚洲自拍av在线 | 国产一级高清视频 | 久久久免费看视频 | 国产精品久久久久久久久久不蜜月 | 91精品国产麻豆国产自产影视 | 在线播放第一页 | 精品久久久久久一区二区里番 | 在线观看黄色大片 | 久久综合爱| 国产精品一区二区免费在线观看 | 久久久免费观看完整版 | 99精品在线免费在线观看 | 欧美一二三视频 | 一区二区三区播放 | 免费精品国产va自在自线 | 天天综合网久久 | 久草在线最新视频 | 国产69精品久久久久久久久久 | 新av在线| 国产99一区二区 | av成人资源 | 亚洲人成免费网站 | 亚洲专区在线播放 | www.xxxx欧美 | 国产手机视频在线观看 | 五月宗合网 | 午夜视频在线网站 | 一区二区三区在线视频111 | av在线在线 | 91精品国产综合久久久久久久 | 国外调教视频网站 | 久久在现| 狠狠狠狠狠色综合 | 狠狠操操操 | 一区在线观看 | 日本在线视频网址 | 亚洲精品影视在线观看 | 成人在线免费看 | 91精品久久久久久久91蜜桃 | 久久综合婷婷综合 | 麻豆视频国产在线观看 | www色网站| av在线电影播放 | 婷婷四房综合激情五月 | 国产大片免费久久 | 亚洲精选久久 | 国产极品尤物在线 | 综合在线亚洲 | 久久精品99北条麻妃 | 91亚洲影院| 欧美专区日韩专区 | 99久久久久免费精品国产 | 精品国产乱码 | 国产色妞影院wwwxxx | 日韩欧美视频免费看 | 天天爱天天 | 国产美女精彩久久 | 国产成人在线免费观看 | 一区二区精| 麻豆91精品91久久久 | 超碰在线天天 | 91精品播放 | 一级黄色片毛片 | 欧美激情综合五月色丁香 | 亚洲极色 | 99欧美精品| 日韩精品 在线视频 | 日韩欧美视频在线免费观看 | 亚洲国产中文字幕在线观看 | 国产va在线 | 国产一区欧美一区 | 91久久爱热色涩涩 | 欧美日韩aaaa | 国产在线第三页 | 国产区av在线 | 91xav| 中国一级片在线播放 | 久久超碰99 | 亚洲成人免费 | 国产在线999 | 亚洲黄色app | 伊人色综合久久天天网 | 久草在线这里只有精品 | 成人永久在线 | 激情综合六月 | 九九免费在线观看 | 99精品久久久久久久 | 中文字幕在线观看的网站 | 一本色道久久综合亚洲二区三区 | 高清一区二区三区av | 午夜精品久久久久久久久久久久 | 五月婷婷综合在线视频 | 欧美精品三级在线观看 | 欧美性成人 | 操少妇视频 | 一级性生活片 | 九九国产视频 | 天天综合区 | 亚洲精品国产精品国自产在线 | 中文字幕在线日亚洲9 | 999在线观看视频 | 日韩欧美一区二区三区视频 | 91网免费观看 | 1024在线看片 | 日韩中文字幕第一页 | 亚洲色图色| 欧美激情另类文学 | 国产精品久久久久久久久免费 | 国产丝袜制服在线 | 欧美激情精品久久久久久变态 | 午夜影院一级 | 美州a亚洲一视本频v色道 | 日韩免费网站 | 久久久久久久久久影院 | 97色涩 | 西西www4444大胆视频 | 五月婷婷在线观看视频 | 国精产品999国精产品视频 | 欧美日韩在线精品一区二区 | av色图天堂网 | 久久影院中文字幕 | 在线成人短视频 | 有码中文字幕在线观看 | 一本一本久久aa综合精品 | 色www永久免费 | 日韩中文字幕电影 | 丝袜网站在线观看 | 久久久久一区二区三区四区 | 欧美成人亚洲成人 | 韩日电影在线 | 日日躁夜夜躁xxxxaaaa | 午夜少妇一区二区三区 | 久久成人免费视频 | 日韩成人不卡 | 91成人蝌蚪 | 久久久久国产精品一区 | 夜添久久精品亚洲国产精品 | 日日综合网 | 国产午夜三级一区二区三桃花影视 | 久久综合九色综合97_ 久久久 | 福利久久久 | 97成人免费视频 | 国产区 在线 | 日本中文字幕系列 | 欧美日产一区 | 久久天天操 | aa一级片 | 欧美最新大片在线看 | 九九九热精品免费视频观看网站 | 丁香六月婷婷开心 | 日日夜夜综合网 | 国产大陆亚洲精品国产 | 婷婷激情影院 | 精品91久久久久 | 国产一区二区不卡在线 | 精品视频在线免费 | 日韩手机在线 | 午夜久久久久久久 | 你操综合 | 黄a网站| 国产精品久久久久久妇 | 日韩av一区在线观看 | 国产日本高清 | 涩涩爱夜夜爱 | 在线观看免费国产小视频 | 国产精品色婷婷视频 | 极品久久久久久久 | 片网址| 婷婷网站天天婷婷网站 | 人人澡人人添人人爽一区二区 | 国产亚洲精品无 | 精品国产一区二 | 天堂av在线免费 |