1. 程式人生 > >從ffmpeg中抽取出來的UDP組播接收程式

從ffmpeg中抽取出來的UDP組播接收程式

前言
程式碼抽取方法:
1. 跟蹤並複製
   跟蹤要抽取程式碼的主要流程, 將主流程相關的,函式層次不是很深的程式碼原樣複製到新的工程中;
   函式呼叫層次很複雜的函式可以先只留下函式介面,將函式體的內容全部註釋掉。
2. 編譯
   編譯新的工程,一個一個解決編譯提示的警告和出錯資訊。
3. 除錯
   使用除錯工具,同步除錯原工程和新工程,將新工程註釋掉函式體的函式補全。
4. 優化完成


下面是從ffmpeg抽取出來的udp組播接收程式。
/******************************************************************************

 * \File
 *   main.c
 * \Brief
 *   Recording udp-multicast data to a file
 * \Author
 *   Hank
 * \Created date
 *   2013-02-25
 ******************************************************************************
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include <errno.h>
#include <memory.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#ifndef AI_PASSIVE
#define AI_PASSIVE 1
#endif


#ifndef NI_NUMERICSERV
#define NI_NUMERICSERV 8
#endif

#define UDP_TX_BUF_SIZE 32768
#define UDP_MAX_PKT_SIZE 65536

#ifndef IN_MULTICAST
#define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
#endif

#define HAVE_AVX 1
#define HAVE_PTHREADS 1
#define ALIGN (HAVE_AVX ? 32 : 16)

#define AVIO_FLAG_READ  1       /**< read-only */
#define AVERROR(e) (-(e))   ///< Returns a negative error code from a POSIX error code, to return from library functions.
#define closesocket close
#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
#define ff_neterrno() AVERROR(errno)

typedef struct AVFifoBuffer {
  uint8_t *buffer;
  uint8_t *rptr, *wptr, *end;
  uint32_t rndx, wndx;
} AVFifoBuffer;


typedef struct {
  int udp_fd;
  int ttl;
  int buffer_size;
  int is_multicast;
  /*Added by Anderson, Fixed udp multicast*/
  int  b_localaddr_flag;
  char local_addr[20];
  /*end*/


  int local_port;
  int reuse_socket;
  struct sockaddr_storage dest_addr;
  int dest_addr_len;
  int is_connected;


  /* Circular Buffer variables for use in UDP receive code */
  int circular_buffer_size;
  AVFifoBuffer *fifo;
  int circular_buffer_error;
  #if HAVE_PTHREADS
  pthread_t circular_buffer_thread;
  #endif
} UDPContext;


typedef struct URLContext {
  int flags;
  int is_streamed;            /**< true if streamed (no seek possible), default = false */
  int max_packet_size;          /**< if non zero, the stream is packetized with this max packet size */
  void *priv_data;
  int is_connected;
} URLContext;


static int default_interrupt_cb(void);
int (*url_interrupt_cb)(void) = default_interrupt_cb;


int udp_set_url(struct sockaddr_storage *addr,
const char *hostname, int port);
int ff_is_multicast_address(struct sockaddr *addr);


/**         
 * If no filename is given to av_open_input_file because you want to
 * get the local port first, then you must call this function to set
 * the remote server address.
 *      
 * url syntax: udp://host:port[?option=val...]
 * option: 'ttl=n'       : set the ttl value (for multicast only)                                                                                 
 *         'localport=n' : set the local port
 *         'pkt_size=n'  : set max packet size
 *         'reuse=1'     : enable reusing the socket
 *      
 * @param h media file context
 * @param uri of the remote server
 * @return zero if no error.
 */ 
int ff_udp_set_remote_url(URLContext *h, const char *uri)
{   
  UDPContext *s = h->priv_data;
  char hostname[256], buf[10];
  int port;
  const char *p;


  //av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
  strcpy(hostname, "225.1.1.31");
  port = 1234;


  /* set the destination address */
  s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port);
  if (s->dest_addr_len < 0) {
  return AVERROR(EIO);
  }   
  s->is_multicast = ff_is_multicast_address((struct sockaddr*) &s->dest_addr);


  return 0; 
}


struct addrinfo* udp_resolve_host(const char *hostname, int port,
int type, int family, int flags)
{
  struct addrinfo hints, *res = 0;
  int error;
  char sport[16];
  const char *node = 0, *service = "0";


  if (port > 0) 
  {
    snprintf(sport, sizeof(sport), "%d", port);
    service = sport;
  }
  if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) 
  {
    node = hostname;
  }


  memset(&hints, 0, sizeof(hints));
  hints.ai_socktype = type;
  hints.ai_family   = family;
  hints.ai_flags = flags;
  if ((error = getaddrinfo(node, service, &hints, &res))) 
  {
    res = NULL;
    //av_log(NULL, AV_LOG_ERROR, "udp_resolve_host: %s\n", gai_strerror(error));
    fprintf(stderr, "udp_resolve_host: %s\n", strerror(error));
  }

  return res;
}   


int udp_set_url(struct sockaddr_storage *addr,
const char *hostname, int port)
{   
  struct addrinfo *res0;
  int addr_len;


  res0 = udp_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
  if (res0 == 0) 
    return AVERROR(EIO);


  memcpy(addr, res0->ai_addr, res0->ai_addrlen);
  addr_len = res0->ai_addrlen;
  freeaddrinfo(res0);


  return addr_len;
}


int ff_is_multicast_address(struct sockaddr *addr)
{                   
  if (addr->sa_family == AF_INET) {
    return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
  }
  return 0;
}

int udp_socket_create(UDPContext *s, 
struct sockaddr_storage *addr, int *addr_len)

  int udp_fd = -1;
  struct addrinfo *res0 = NULL, *res = NULL; 
  int family = AF_UNSPEC;


  if (((struct sockaddr *) &s->dest_addr)->sa_family)
    family = ((struct sockaddr *) &s->dest_addr)->sa_family;


  res0 = udp_resolve_host(0, s->local_port, SOCK_DGRAM, family, AI_PASSIVE);
  if (res0 == 0)
    goto fail;


  for (res = res0; res; res=res->ai_next) 
  {
    udp_fd = socket(res->ai_family, SOCK_DGRAM, 0);
    if (udp_fd > 0) 
      break;
    //av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno));
    fprintf(stderr, "socket: %s\n", strerror(errno));
  }


  if (udp_fd < 0)
    goto fail;


  memcpy(addr, res->ai_addr, res->ai_addrlen);
  *addr_len = res->ai_addrlen;
  freeaddrinfo(res0);


  return udp_fd; 


fail:
  if (udp_fd >= 0)
   closesocket(udp_fd);                                                                                                                      
  if(res0)
   freeaddrinfo(res0);
  return -1;
}     


int udp_port(struct sockaddr_storage *addr, int addr_len) 
{   
  char sbuf[sizeof(int)*3+1];


  if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0,  sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) {
    //av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno));
    fprintf(stderr, "getnameinfo: %s\n", strerror(errno));
    return -1;
  }


  return strtol(sbuf, NULL, 10);
}




int udp_join_multicast_group(int sockfd, struct sockaddr *addr, int b_localaddr, char *pc_local_addr)
{
  #ifdef IP_ADD_MEMBERSHIP 
  if (addr->sa_family == AF_INET) {
    struct ip_mreq mreq;


    mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
    if ( 0 == b_localaddr )
    {   
      mreq.imr_interface.s_addr= INADDR_ANY; 
    } 
    else
    { 
      mreq.imr_interface.s_addr= inet_addr(pc_local_addr);
    }


    if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
      //av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
      fprintf(stderr, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
      return -1;
    }

相關推薦

ffmpeg抽取出來UDP接收程式

前言 程式碼抽取方法: 1. 跟蹤並複製    跟蹤要抽取程式碼的主要流程, 將主流程相關的,函式層次不是很深的程式碼原樣複製到新的工程中;    函式呼叫層次很複雜的函式可以先只留下函式介面,將函式體的內容全部註釋掉。 2. 編譯    編譯新的工程,一個一

UDP接收端解析

網路中的一臺主機如果希望能夠接收到來自網路中其它主機發往某一個組播組的資料報,那麼這麼主機必須先加入該組播組,然後就可以從組地址接收資料包。在廣域網中,還涉及到路由器支援組播路由等,但本文希望以一個最為簡單的例子解釋清楚協議棧關於組播的一個最為簡單明瞭的工作過程,甚至,我們不希望涉及到 IGMP包。

linux udp接收問題及原理分析

現象: 在某個網路環境下,同一個udp組播源(igmpv2),同樣的收流程式碼,在windows上能收到,linux上收不到。排除網路拓撲結構、程式語言、硬體驅動等問題,我們就此問題來分析原理及解決方案。 環境: 交換機出,組播地址224.X.X.X,機器多網絡卡,eth

android 開啟一個任意檔案,環信抽取出來

android 開啟一個任意檔案,從環信中抽取出來的 1.使用方法 File file = new File(Environment.getExternalStorageDirectory(), "/4873641464161346955.jpg");

H.264流媒體UDPffmpeg解碼實驗

簡介:將H.264視訊流從傳送端通過UDP組播到接收端,並通過ffmpeg解碼播放。 分為四步: 1 路由器端區域網下設定虛擬伺服器 2 TCP/UDP通訊測試 3 傳送端與接收端ffmpeg的安裝 4 通過指令對H264流媒體組播和解碼 第一步:區域網下設定虛擬伺服器

GitHub整理出來的15個最受歡迎的Python開源框架,你喜歡哪個

python 開源 框架 爬蟲 web 從GitHub中整理出的15個最受歡迎的Python開源框架。這些框架包括事件I/O,OLAP,Web開發,高性能網絡通信,測試,爬蟲等。Django: Python Web應用開發框架Django 應該是最出名的Python框架,GAE甚至Erla

【程式設計筆記】執行緒池實現原始碼(POCO剝離出來

原始碼下載:https://download.csdn.net/download/fzuim/10625204 CThreadPool類 /***************************************************************

JAVA---面向物件之生活抽取例項物件

public class Car{ private String brand; private int num; private String colour; private int seats; //建構函式 public Car(String brand){

致職場失意者 如何迷茫出來

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

桌面共享UDP實現

組播(Multicast)傳輸:在傳送者和每一接收者之間實現點對多點網路連線。如果一臺傳送者同時給多個的接收者傳輸相同的資料,也只需複製一份的相同資料包。它提高了資料傳送效率。減少了骨幹網路出現擁塞的可能性。   廣播(Broadcast)傳輸:是指在IP子網內廣播資料包,所有在子網內部的主機都

UDP ---你需要了解這些

先來了解下UDP UDP 是UserDatagram Protocol的簡稱, 中文名是使用者資料報協議,是OSI(Open System Interconnection,開放式系統互聯) 參考模型中一種無連線的傳輸層協議,提供面向事務的簡單不可靠資訊傳送服務,IETF

vlc使用udp方式傳送ts流的特殊規則

當你寫程式去接收vlc傳送的ts流時,你會發現解析出來的一幀視訊幀有時候解碼會失敗,追究其原因,是因為前4個位元組不是0,0,0,1。 那為什麼會這樣呢? 這是因為vlc在處理大於65535位元組的視訊幀時,沒有按照ISO標準來。 ISO標準的做法是將PES_packe

linux下怎麼使用C語言編寫接收和傳送udp資料?

一,傳送端 程式碼如下: 先呼叫initUdpMultiCastSender初始化, int initUdpMultiCastSender(uint32_t localip,uint16_t localport) { int sockfd = socket(AF_

Qml實用技巧:將樣式style物件獨立出來,可使多個按鈕載入同一個樣式

需求         多個按鈕使用同一個樣式 原理         寫成元件形式(在或不在當前檔案中),需要樣式時,Button載入style即可 程式碼 Item { Rectangle {

MFC中用Asyncsocket類實現udp

程式碼: void CUDPGroupDlg::OnBnClickedButton1() { //加入組播 bool opt = TRUE; ip_mreq setip; udpsocket.Create(CASTPORT,SOCK_DGRAM, FD_RE

udp流(MPTS)進行簡單的收錄

1 確認udp組播流共有幾個program: 使用vlc開啟udp組播流 檢視編碼器資訊 確認udp組播流的各個program: 可以看出來,該udp組播流共有3個program,分別是:211,

課堂/會議同屏教學解決方案之RTSP/RTP over UDP解決方案

問題 在之前的部落格《EasyIPCamera實現Windows PC桌面、安卓Android桌面同屏直播,助力無紙化會議系統》我們描述了一套基於EasyIPCamera的同屏功能,但是這個可以說只是一個功能實現,並不能用於實際的現場應用,因為再強的流媒體伺服

關於QT UDP的幾個問題

UDP組播時最好不要提客戶端/服務端的概念,而是提傳送端/接收端的概念,避免出現邏輯理解混亂。傳送端也需要接收,實際使用的過程中還是得根據業務提服務端/客戶端。組播時A端和B端,都可能收發,把它們都加入組播組就可以了,能夠達到既能接收也能傳送的要求。 注

android out目錄原始碼分離出來

Android系統編譯成功後的程式碼預設放在原始碼目錄下的out目錄中,我們需要將out目錄分離出來,可以在環境變數中新增 OUT_DIR_COMMON_BASE="/androidsource/out",如果你的工作目錄中存在 /work/android_branch1,

labview UDP程式設計簡介

簡介        IP網路傳輸方式共分為單播,組播(多播),廣播三種。平時我們最常用的一對一的網路傳輸方式就是屬於單播;而組播是一對多的傳輸方式,其中有個組播組的 概念,傳送端將資料向一個組內傳送,網路中的路由器通過底層的IGMP協議自動將資料傳送到所有監聽這個組的終端。