Fixed to compile with recent ffmpeg

git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@2601 e3e1d417-86f3-4887-817a-d78f3d33393f
This commit is contained in:
stan 2008-07-24 16:57:39 +00:00
parent 8a1b646834
commit 4c2c4199ca
10 changed files with 649 additions and 161 deletions

View File

@ -210,6 +210,7 @@ AC_CHECK_LIB(avutil,ff_gcd,,AC_MSG_WARN(libavutil.a may be required for MPEG str
AC_CHECK_LIB(avcodec,avcodec_init,,AC_MSG_WARN(libavcodec.a is required for MPEG streaming))
AC_CHECK_LIB(avformat,av_new_stream,,AC_MSG_WARN(libavformat.a is required for MPEG streaming),-lavcodec)
AC_CHECK_LIB(swscale,sws_scale,,,-lswscale)
AC_CHECK_LIB(bz2,BZ2_bzCompress,,AC_MSG_WARN(zm requires libbz2.a for recent versions of ffmpeg))
# Checks for header files.
AC_FUNC_ALLOCA
@ -218,12 +219,14 @@ AC_CHECK_HEADERS([fcntl.h limits.h memory.h netdb.h netinet/in.h stddef.h stdlib
AC_CHECK_HEADERS(linux/videodev.h,,AC_MSG_ERROR(zm requires Video4Linux to be installed),)
AC_CHECK_HEADERS(linux/videodev2.h,,AC_MSG_WARN(zm requires Video4Linux2 to be installed for V4L2 support),)
AC_CHECK_HEADERS(mysql/mysql.h,,AC_MSG_ERROR(zm requires MySQL headers - check that MySQL development packages are installed),)
AC_CHECK_HEADERS(ffmpeg/avcodec.h,,,)
AC_CHECK_HEADERS(libavutil/avutil.h,,,)
AC_CHECK_HEADERS(ffmpeg/avutil.h,,,)
AC_CHECK_HEADERS(libavcodec/avcodec.h,,,)
AC_CHECK_HEADERS(ffmpeg/avformat.h,,,)
AC_CHECK_HEADERS(ffmpeg/avcodec.h,,,)
AC_CHECK_HEADERS(libavformat/avformat.h,,,)
AC_CHECK_HEADERS(ffmpeg/swscale.h,,,)
AC_CHECK_HEADERS(ffmpeg/avformat.h,,,)
AC_CHECK_HEADERS(libswscale/swscale.h,,,)
AC_CHECK_HEADERS(ffmpeg/swscale.h,,,)
AC_CHECK_HEADERS(pcre/pcre.h,,,)
AC_CHECK_HEADERS(pcre.h,,,)
if test "$ENABLE_MMAP" = "yes"; then

View File

@ -48,7 +48,7 @@ zm_SOURCES = \
zm_rtp_data.cpp \
zm_rtp_source.cpp \
zm_rtsp.cpp \
zm_sdp.cpp \
zm_sdp.c \
zm_signal.cpp \
zm_stream.cpp \
zm_thread.cpp \
@ -101,7 +101,7 @@ noinst_HEADERS = \
zm_rtp.h \
zm_rtp_source.h \
zm_rtsp.cpp \
zm_sdp.cpp \
zm_sdp.c \
zm_signal.h \
zm_stream.h \
zm_thread.h \

View File

@ -17,15 +17,19 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "zm.h"
#if HAVE_LIBAVCODEC
#ifndef ZM_FFMPEG_H
#define ZM_FFMPEG_H
#if HAVE_LIBAVCODEC
extern "C" {
#define __STDC_CONSTANT_MACROS
#if HAVE_LIBAVUTIL_AVUTIL_H
#include <libavutil/avutil.h>
#elif HAVE_FFMPEG_AVUTIL_H
#include <ffmpeg/avutil.h>
#else
#error "No location for avutils.h found"
#endif
#if HAVE_LIBAVCODEC_AVCODEC_H
#include <libavcodec/avcodec.h>
#elif HAVE_FFMPEG_AVCODEC_H
@ -62,7 +66,7 @@ extern "C" {
#else // FFMPEG_VERSION_INT
#define ZM_FFMPEG_SVN 1
#endif // FFMPEG_VERSION_INT
#endif // ZM_FFMPEG_H
#endif // HAVE_LIBAVCODEC
#endif // ZM_FFMPEG_H

View File

@ -17,13 +17,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#if HAVE_LIBAVCODEC
#ifndef ZM_MPEG_H
#define ZM_MPEG_H
#include "zm_ffmpeg.h"
#if HAVE_LIBAVCODEC
class VideoStream
{
protected:
@ -65,6 +65,6 @@ public:
double EncodeFrame( uint8_t *buffer, int buffer_size, bool add_timestamp=false, unsigned int timestamp=0 );
};
#endif // ZM_MPEG_H
#endif // HAVE_LIBAVCODEC
#endif // ZM_MPEG_H

View File

@ -20,7 +20,9 @@
#include "zm_remote_camera_rtsp.h"
#include "zm_mem_utils.h"
extern "C" {
#include "zm_sdp.h"
}
#include <sys/types.h>
#include <sys/socket.h>

View File

@ -24,6 +24,7 @@
#include "zm_db.h"
#include <sys/time.h>
#include <stdlib.h>
#include <errno.h>
int RtspThread::mMinDataPort = 0;

View File

@ -17,10 +17,13 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
#ifndef ZM_RTP_RTSP_H
#define ZM_RTP_RTSP_H
#ifndef ZM_RTSP_H
#define ZM_RTSP_H
extern "C" {
#include "zm_sdp.h"
}
#include "zm_mpeg.h"
#include "zm_comms.h"
#include "zm_thread.h"
@ -122,4 +125,4 @@ public:
}
};
#endif // ZM_RTP_RTSP_H
#endif // ZM_RTSP_H

View File

@ -1,40 +1,30 @@
#include "zm_ffmpeg.h"
#include "zm_sdp.h"
//
// This file contains chunks of ffmpeg code that are not currently exported.
// The main thing we are after is the sdp parser
//
#if HAVE_LIBAVUTIL_AVUTIL_H
#include <libavutil/avstring.h>
#elif HAVE_FFMPEG_AVUTIL_H
#include <ffmpeg/avstring.h>
#else
#error "No location for avstring.h found"
#endif
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <arpa/inet.h>
static int inet_aton (const char * str, struct in_addr * add)
{
unsigned int add1 = 0, add2 = 0, add3 = 0, add4 = 0;
//
// Part of libavformat/avformat.h that is usually obscured
//
if (sscanf(str, "%d.%d.%d.%d", &add1, &add2, &add3, &add4) != 4)
return 0;
if (!add1 || (add1|add2|add3|add4) > 255) return 0;
add->s_addr=(add4<<24)+(add3<<16)+(add2<<8)+add1;
return 1;
}
static void __dynarray_add(unsigned long **tab_ptr, int *nb_ptr, unsigned long elem)
{
int nb, nb_alloc;
unsigned long *tab;
nb = *nb_ptr;
tab = *tab_ptr;
if ((nb & (nb - 1)) == 0) {
if (nb == 0)
nb_alloc = 1;
else
nb_alloc = nb * 2;
tab = (long unsigned int *)av_realloc(tab, nb_alloc * sizeof(unsigned long));
*tab_ptr = tab;
}
tab[nb++] = elem;
*nb_ptr = nb;
}
void ff_dynarray_add(unsigned long **tab_ptr, int *nb_ptr, unsigned long elem);
#ifdef __GNUC__
#define dynarray_add(tab, nb_ptr, elem)\
@ -42,79 +32,71 @@ do {\
typeof(tab) _tab = (tab);\
typeof(elem) _elem = (elem);\
(void)sizeof(**_tab == _elem); /* check that types are compatible */\
__dynarray_add((unsigned long **)_tab, nb_ptr, (unsigned long)_elem);\
ff_dynarray_add((unsigned long **)_tab, nb_ptr, (unsigned long)_elem);\
} while(0)
#else
#define dynarray_add(tab, nb_ptr, elem)\
do {\
__dynarray_add((unsigned long **)(tab), nb_ptr, (unsigned long)(elem));\
ff_dynarray_add((unsigned long **)(tab), nb_ptr, (unsigned long)(elem));\
} while(0)
#endif
static void url_split(char *proto, int proto_size,
time_t mktimegm(struct tm *tm);
struct tm *brktimegm(time_t secs, struct tm *tm);
const char *small_strptime(const char *p, const char *fmt,
struct tm *dt);
struct in_addr;
int resolve_host(struct in_addr *sin_addr, const char *hostname);
void url_split(char *proto, int proto_size,
char *authorization, int authorization_size,
char *hostname, int hostname_size,
int *port_ptr,
char *path, int path_size,
const char *url)
const char *url);
//
// Part of libavformat/rtsp.c
//
//#include <sys/time.h>
//#include <unistd.h> /* for select() prototype */
//#include "network.h"
typedef struct RTSPStream {
URLContext *rtp_handle; /* RTP stream handle */
RTPDemuxContext *rtp_ctx; /* RTP parse context */
int stream_index; /* corresponding stream index, if any. -1 if none (MPEG2TS case) */
int interleaved_min, interleaved_max; /* interleave ids, if TCP transport */
char control_url[1024]; /* url for this stream (from SDP) */
int sdp_port; /* port (from SDP content - not used in RTSP) */
struct in_addr sdp_ip; /* IP address (from SDP content - not used in RTSP) */
int sdp_ttl; /* IP TTL (from SDP content - not used in RTSP) */
int sdp_payload_type; /* payload type - only used in SDP */
rtp_payload_data_t rtp_payload_data; /* rtp payload parsing infos from SDP */
RTPDynamicProtocolHandler *dynamic_handler; ///< Only valid if it's a dynamic protocol. (This is the handler structure)
void *dynamic_protocol_context; ///< Only valid if it's a dynamic protocol. (This is any private data associated with the dynamic protocol)
} RTSPStream;
static int rtsp_read_play(AVFormatContext *s);
/* XXX: currently, the only way to change the protocols consists in
changing this variable */
static int rtsp_probe(AVProbeData *p)
{
const char *p, *ls, *at, *col, *brk;
if (port_ptr) *port_ptr = -1;
if (proto_size > 0) proto[0] = 0;
if (authorization_size > 0) authorization[0] = 0;
if (hostname_size > 0) hostname[0] = 0;
if (path_size > 0) path[0] = 0;
/* parse protocol */
if ((p = strchr(url, ':'))) {
av_strlcpy(proto, url, FFMIN(proto_size, p + 1 - url));
p++; /* skip ':' */
if (*p == '/') p++;
if (*p == '/') p++;
} else {
/* no protocol means plain filename */
av_strlcpy(path, url, path_size);
return;
}
/* separate path from hostname */
ls = strchr(p, '/');
if(!ls)
ls = strchr(p, '?');
if(ls)
av_strlcpy(path, ls, path_size);
else
ls = &p[strlen(p)]; // XXX
/* the rest is hostname, use that to parse auth/port */
if (ls != p) {
/* authorization (user[:pass]@hostname) */
if ((at = strchr(p, '@')) && at < ls) {
av_strlcpy(authorization, p,
FFMIN(authorization_size, at + 1 - p));
p = at + 1; /* skip '@' */
}
if (*p == '[' && (brk = strchr(p, ']')) && brk < ls) {
/* [host]:port */
av_strlcpy(hostname, p + 1,
FFMIN(hostname_size, brk - p));
if (brk[1] == ':' && port_ptr)
*port_ptr = atoi(brk + 2);
} else if ((col = strchr(p, ':')) && col < ls) {
av_strlcpy(hostname, p,
FFMIN(col + 1 - p, hostname_size));
if (port_ptr) *port_ptr = atoi(col + 1);
} else
av_strlcpy(hostname, p,
FFMIN(ls + 1 - p, hostname_size));
}
if (av_strstart(p->filename, "rtsp:", NULL))
return AVPROBE_SCORE_MAX;
return 0;
}
static int redir_isspace(int c)
{
return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}
static void skip_spaces(const char **pp)
@ -224,8 +206,6 @@ static int sdp_parse_rtpmap(AVCodecContext *codec, RTSPStream *rtsp_st, int payl
break;
case CODEC_TYPE_VIDEO:
av_log(codec, AV_LOG_DEBUG, " video codec set to : %s\n", c_name);
// Total hack here I suspect
codec->sample_rate = i;
break;
default:
break;
@ -273,7 +253,7 @@ static void sdp_parse_fmtp_config(AVCodecContext *codec, char *attr, char *value
if (!strcmp(attr, "config")) {
/* decode the hexa encoded parameter */
int len = hex_to_data(NULL, value);
codec->extradata = (uint8_t *)av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
if (!codec->extradata)
return;
codec->extradata_size = len;
@ -314,7 +294,7 @@ static void sdp_parse_fmtp(AVStream *st, const char *p)
char value[4096];
int i;
RTSPStream *rtsp_st = (RTSPStream *)st->priv_data;
RTSPStream *rtsp_st = st->priv_data;
AVCodecContext *codec = st->codec;
rtp_payload_data_t *rtp_payload_data = &rtsp_st->rtp_payload_data;
@ -370,7 +350,7 @@ typedef struct SDPParseState {
static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
int letter, const char *buf)
{
RTSPState *rt = (RTSPState *)s->priv_data;
RTSPState *rt = s->priv_data;
char buf1[64], st_type[64];
const char *p;
int codec_type, payload_type, i;
@ -406,7 +386,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
s1->default_ttl = ttl;
} else {
st = s->streams[s->nb_streams - 1];
rtsp_st = (RTSPStream *)st->priv_data;
rtsp_st = st->priv_data;
rtsp_st->sdp_ip = sdp_ip;
rtsp_st->sdp_ttl = ttl;
}
@ -430,7 +410,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
} else {
return;
}
rtsp_st = (RTSPStream *)av_mallocz(sizeof(RTSPStream));
rtsp_st = av_mallocz(sizeof(RTSPStream));
if (!rtsp_st)
return;
rtsp_st->stream_index = -1;
@ -456,7 +436,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
return;
st->priv_data = rtsp_st;
rtsp_st->stream_index = st->index;
st->codec->codec_type = (CodecType)codec_type;
st->codec->codec_type = codec_type;
if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) {
/* if standard payload type, we can find the codec right now */
rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type);
@ -470,7 +450,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
char proto[32];
/* get the control url */
st = s->streams[s->nb_streams - 1];
rtsp_st = (RTSPStream *)st->priv_data;
rtsp_st = st->priv_data;
/* XXX: may need to add full url resolution */
url_split(proto, sizeof(proto), NULL, 0, NULL, 0, NULL, NULL, 0, p);
@ -487,7 +467,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
payload_type = atoi(buf1);
for(i = 0; i < s->nb_streams;i++) {
st = s->streams[i];
rtsp_st = (RTSPStream *)st->priv_data;
rtsp_st = st->priv_data;
if (rtsp_st->sdp_payload_type == payload_type) {
sdp_parse_rtpmap(st->codec, rtsp_st, payload_type, p);
}
@ -498,7 +478,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
payload_type = atoi(buf1);
for(i = 0; i < s->nb_streams;i++) {
st = s->streams[i];
rtsp_st = (RTSPStream *)st->priv_data;
rtsp_st = st->priv_data;
if (rtsp_st->sdp_payload_type == payload_type) {
if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) {
if(!rtsp_st->dynamic_handler->parse_sdp_a_line(st, rtsp_st->dynamic_protocol_context, buf)) {
@ -515,7 +495,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
payload_type = atoi(buf1);
for(i = 0; i < s->nb_streams;i++) {
st = s->streams[i];
rtsp_st = (RTSPStream *)st->priv_data;
rtsp_st = st->priv_data;
if (rtsp_st->sdp_payload_type == payload_type) {
if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) {
rtsp_st->dynamic_handler->parse_sdp_a_line(st, rtsp_st->dynamic_protocol_context, buf);
@ -589,3 +569,434 @@ static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp)
}
*pp = p;
}
/* XXX: only one transport specification is parsed */
static void rtsp_parse_transport(RTSPHeader *reply, const char *p)
{
char transport_protocol[16];
char profile[16];
char lower_transport[16];
char parameter[16];
RTSPTransportField *th;
char buf[256];
reply->nb_transports = 0;
for(;;) {
skip_spaces(&p);
if (*p == '\0')
break;
th = &reply->transports[reply->nb_transports];
get_word_sep(transport_protocol, sizeof(transport_protocol),
"/", &p);
if (*p == '/')
p++;
if (!strcasecmp (transport_protocol, "rtp")) {
get_word_sep(profile, sizeof(profile), "/;,", &p);
lower_transport[0] = '\0';
/* rtp/avp/<protocol> */
if (*p == '/') {
p++;
get_word_sep(lower_transport, sizeof(lower_transport),
";,", &p);
}
} else if (!strcasecmp (transport_protocol, "x-pn-tng")) {
/* x-pn-tng/<protocol> */
get_word_sep(lower_transport, sizeof(lower_transport), "/;,", &p);
profile[0] = '\0';
}
if (!strcasecmp(lower_transport, "TCP"))
th->protocol = RTSP_PROTOCOL_RTP_TCP;
else
th->protocol = RTSP_PROTOCOL_RTP_UDP;
if (*p == ';')
p++;
/* get each parameter */
while (*p != '\0' && *p != ',') {
get_word_sep(parameter, sizeof(parameter), "=;,", &p);
if (!strcmp(parameter, "port")) {
if (*p == '=') {
p++;
rtsp_parse_range(&th->port_min, &th->port_max, &p);
}
} else if (!strcmp(parameter, "client_port")) {
if (*p == '=') {
p++;
rtsp_parse_range(&th->client_port_min,
&th->client_port_max, &p);
}
} else if (!strcmp(parameter, "server_port")) {
if (*p == '=') {
p++;
rtsp_parse_range(&th->server_port_min,
&th->server_port_max, &p);
}
} else if (!strcmp(parameter, "interleaved")) {
if (*p == '=') {
p++;
rtsp_parse_range(&th->interleaved_min,
&th->interleaved_max, &p);
}
} else if (!strcmp(parameter, "multicast")) {
if (th->protocol == RTSP_PROTOCOL_RTP_UDP)
th->protocol = RTSP_PROTOCOL_RTP_UDP_MULTICAST;
} else if (!strcmp(parameter, "ttl")) {
if (*p == '=') {
p++;
th->ttl = strtol(p, (char **)&p, 10);
}
} else if (!strcmp(parameter, "destination")) {
struct in_addr ipaddr;
if (*p == '=') {
p++;
get_word_sep(buf, sizeof(buf), ";,", &p);
if (inet_aton(buf, &ipaddr))
th->destination = ntohl(ipaddr.s_addr);
}
}
while (*p != ';' && *p != '\0' && *p != ',')
p++;
if (*p == ';')
p++;
}
if (*p == ',')
p++;
reply->nb_transports++;
}
}
static int url_readbuf(URLContext *h, unsigned char *buf, int size)
{
int ret, len;
len = 0;
while (len < size) {
ret = url_read(h, buf+len, size-len);
if (ret < 1)
return ret;
len += ret;
}
return len;
}
/* skip a RTP/TCP interleaved packet */
static void rtsp_skip_packet(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
int ret, len, len1;
uint8_t buf[1024];
ret = url_readbuf(rt->rtsp_hd, buf, 3);
if (ret != 3)
return;
len = AV_RB16(buf + 1);
#ifdef DEBUG
printf("skipping RTP packet len=%d\n", len);
#endif
/* skip payload */
while (len > 0) {
len1 = len;
if (len1 > sizeof(buf))
len1 = sizeof(buf);
ret = url_readbuf(rt->rtsp_hd, buf, len1);
if (ret != len1)
return;
len -= len1;
}
}
static void rtsp_send_cmd(AVFormatContext *s,
const char *cmd, RTSPHeader *reply,
unsigned char **content_ptr)
{
RTSPState *rt = s->priv_data;
char buf[4096], buf1[1024], *q;
unsigned char ch;
const char *p;
int content_length, line_count;
unsigned char *content = NULL;
memset(reply, 0, sizeof(RTSPHeader));
rt->seq++;
av_strlcpy(buf, cmd, sizeof(buf));
snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq);
av_strlcat(buf, buf1, sizeof(buf));
if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id);
av_strlcat(buf, buf1, sizeof(buf));
}
av_strlcat(buf, "\r\n", sizeof(buf));
#ifdef DEBUG
printf("Sending:\n%s--\n", buf);
#endif
url_write(rt->rtsp_hd, buf, strlen(buf));
/* parse reply (XXX: use buffers) */
line_count = 0;
rt->last_reply[0] = '\0';
for(;;) {
q = buf;
for(;;) {
if (url_readbuf(rt->rtsp_hd, &ch, 1) != 1)
break;
if (ch == '\n')
break;
if (ch == '$') {
/* XXX: only parse it if first char on line ? */
rtsp_skip_packet(s);
} else if (ch != '\r') {
if ((q - buf) < sizeof(buf) - 1)
*q++ = ch;
}
}
*q = '\0';
#ifdef DEBUG
printf("line='%s'\n", buf);
#endif
/* test if last line */
if (buf[0] == '\0')
break;
p = buf;
if (line_count == 0) {
/* get reply code */
get_word(buf1, sizeof(buf1), &p);
get_word(buf1, sizeof(buf1), &p);
reply->status_code = atoi(buf1);
} else {
rtsp_parse_line(reply, p);
av_strlcat(rt->last_reply, p, sizeof(rt->last_reply));
av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply));
}
line_count++;
}
if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id));
content_length = reply->content_length;
if (content_length > 0) {
/* leave some room for a trailing '\0' (useful for simple parsing) */
content = av_malloc(content_length + 1);
(void)url_readbuf(rt->rtsp_hd, content, content_length);
content[content_length] = '\0';
}
if (content_ptr)
*content_ptr = content;
else
av_free(content);
}
/* close and free RTSP streams */
static void rtsp_close_streams(RTSPState *rt)
{
int i;
RTSPStream *rtsp_st;
for(i=0;i<rt->nb_rtsp_streams;i++) {
rtsp_st = rt->rtsp_streams[i];
if (rtsp_st) {
if (rtsp_st->rtp_ctx)
rtp_parse_close(rtsp_st->rtp_ctx);
if (rtsp_st->rtp_handle)
url_close(rtsp_st->rtp_handle);
if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
rtsp_st->dynamic_handler->close(rtsp_st->dynamic_protocol_context);
}
}
av_free(rt->rtsp_streams);
}
#ifdef CONFIG_RTSP_DEMUXER
AVInputFormat rtsp_demuxer = {
"rtsp",
NULL_IF_CONFIG_SMALL("RTSP input format"),
sizeof(RTSPState),
rtsp_probe,
rtsp_read_header,
rtsp_read_packet,
rtsp_read_close,
rtsp_read_seek,
.flags = AVFMT_NOFILE,
.read_play = rtsp_read_play,
.read_pause = rtsp_read_pause,
};
#endif
static int sdp_probe(AVProbeData *p1)
{
const char *p = p1->buf, *p_end = p1->buf + p1->buf_size;
/* we look for a line beginning "c=IN IP4" */
while (p < p_end && *p != '\0') {
if (p + sizeof("c=IN IP4") - 1 < p_end && av_strstart(p, "c=IN IP4", NULL))
return AVPROBE_SCORE_MAX / 2;
while(p < p_end - 1 && *p != '\n') p++;
if (++p >= p_end)
break;
if (*p == '\r')
p++;
}
return 0;
}
#define SDP_MAX_SIZE 8192
static int sdp_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
RTSPState *rt = s->priv_data;
RTSPStream *rtsp_st;
int size, i, err;
char *content;
char url[1024];
AVStream *st;
/* read the whole sdp file */
/* XXX: better loading */
content = av_malloc(SDP_MAX_SIZE);
size = get_buffer(s->pb, content, SDP_MAX_SIZE - 1);
if (size <= 0) {
av_free(content);
return AVERROR_INVALIDDATA;
}
content[size] ='\0';
sdp_parse(s, content);
av_free(content);
/* open each RTP stream */
for(i=0;i<rt->nb_rtsp_streams;i++) {
rtsp_st = rt->rtsp_streams[i];
snprintf(url, sizeof(url), "rtp://%s:%d?localport=%d&ttl=%d",
inet_ntoa(rtsp_st->sdp_ip),
rtsp_st->sdp_port,
rtsp_st->sdp_port,
rtsp_st->sdp_ttl);
if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) {
err = AVERROR_INVALIDDATA;
goto fail;
}
/* open the RTP context */
st = NULL;
if (rtsp_st->stream_index >= 0)
st = s->streams[rtsp_st->stream_index];
if (!st)
s->ctx_flags |= AVFMTCTX_NOHEADER;
rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->rtp_handle, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data);
if (!rtsp_st->rtp_ctx) {
err = AVERROR(ENOMEM);
goto fail;
} else {
if(rtsp_st->dynamic_handler) {
rtsp_st->rtp_ctx->dynamic_protocol_context= rtsp_st->dynamic_protocol_context;
rtsp_st->rtp_ctx->parse_packet= rtsp_st->dynamic_handler->parse_packet;
}
}
}
return 0;
fail:
rtsp_close_streams(rt);
return err;
}
static int sdp_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
return rtsp_read_packet(s, pkt);
}
static int sdp_read_close(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
rtsp_close_streams(rt);
return 0;
}
#ifdef CONFIG_SDP_DEMUXER
AVInputFormat sdp_demuxer = {
"sdp",
NULL_IF_CONFIG_SMALL("SDP"),
sizeof(RTSPState),
sdp_probe,
sdp_read_header,
sdp_read_packet,
sdp_read_close,
};
#endif
#ifdef CONFIG_REDIR_DEMUXER
/* dummy redirector format (used directly in av_open_input_file now) */
static int redir_probe(AVProbeData *pd)
{
const char *p;
p = pd->buf;
while (redir_isspace(*p))
p++;
if (av_strstart(p, "http://", NULL) ||
av_strstart(p, "rtsp://", NULL))
return AVPROBE_SCORE_MAX;
return 0;
}
static int redir_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
char buf[4096], *q;
int c;
AVFormatContext *ic = NULL;
ByteIOContext *f = s->pb;
/* parse each URL and try to open it */
c = url_fgetc(f);
while (c != URL_EOF) {
/* skip spaces */
for(;;) {
if (!redir_isspace(c))
break;
c = url_fgetc(f);
}
if (c == URL_EOF)
break;
/* record url */
q = buf;
for(;;) {
if (c == URL_EOF || redir_isspace(c))
break;
if ((q - buf) < sizeof(buf) - 1)
*q++ = c;
c = url_fgetc(f);
}
*q = '\0';
//printf("URL='%s'\n", buf);
/* try to open the media file */
if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0)
break;
}
if (!ic)
return AVERROR(EIO);
*s = *ic;
url_fclose(f);
return 0;
}
AVInputFormat redir_demuxer = {
"redir",
NULL_IF_CONFIG_SMALL("Redirector format"),
0,
redir_probe,
redir_read_header,
NULL,
NULL,
};
#endif

View File

@ -1,23 +1,93 @@
#ifndef ZM_SDP_H
#define ZM_SDP_H
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "config.h"
#include "zm_ffmpeg.h"
#include <netinet/in.h>
#if HAVE_LIBAVFORMAT_AVFORMAT_H
#include <libavformat/rtsp.h>
#elif HAVE_FFMPEG_AVFORMAT_H
#include <ffmpeg/rtsp.h>
#else
#error "No location for rtsp.h found"
#endif
extern "C"
//
// This file contains chunks of ffmpeg code that are not currently exported.
// The main thing we are after is the sdp parser
//
//
// Part of libavformat/rtp.h
//
#define RTP_MIN_PACKET_LENGTH 12
#define RTP_MAX_PACKET_LENGTH 1500 /* XXX: suppress this define */
int rtp_get_codec_info(AVCodecContext *codec, int payload_type);
/** return < 0 if unknown payload type */
int rtp_get_payload_type(AVCodecContext *codec);
typedef struct RTPDemuxContext RTPDemuxContext;
typedef struct rtp_payload_data_s rtp_payload_data_s;
RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, URLContext *rtpc, int payload_type, rtp_payload_data_s *rtp_payload_data);
int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
const uint8_t *buf, int len);
void rtp_parse_close(RTPDemuxContext *s);
int rtp_get_local_port(URLContext *h);
int rtp_set_remote_url(URLContext *h, const char *uri);
void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd);
/**
* some rtp servers assume client is dead if they don't hear from them...
* so we send a Receiver Report to the provided ByteIO context
* (we don't have access to the rtcp handle from here)
*/
int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count);
#define RTP_PT_PRIVATE 96
#define RTP_VERSION 2
#define RTP_MAX_SDES 256 /**< maximum text length for SDES */
/* RTCP paquets use 0.5 % of the bandwidth */
#define RTCP_TX_RATIO_NUM 5
#define RTCP_TX_RATIO_DEN 1000
/** Structure listing useful vars to parse RTP packet payload*/
typedef struct rtp_payload_data_s
{
//#include "network.h"
#include "ffmpeg/avstring.h"
#include "ffmpeg/rtsp.h"
int sizelength;
int indexlength;
int indexdeltalength;
int profile_level_id;
int streamtype;
int objecttype;
char *mode;
//#include <stdint.h>
//#include "avcodec.h"
#include "ffmpeg/rtp.h"
}
/** mpeg 4 AU headers */
struct AUHeaders {
int size;
int index;
int cts_flag;
int cts;
int dts_flag;
int dts;
int rap_flag;
int streamstate;
} *au_headers;
int nb_au_headers;
int au_headers_length_bytes;
int cur_au_index;
} rtp_payload_data_t;
//
// Part of libavformat/rtp_internal.h
//
#include <stdint.h>
//#include "rtp.h"
// these statistics are used for rtcp receiver reports...
typedef struct {
@ -111,6 +181,24 @@ struct RTPDemuxContext {
extern RTPDynamicProtocolHandler *RTPFirstDynamicPayloadHandler;
int rtsp_next_attr_and_value(const char **p, char *attr, int attr_size, char *value, int value_size); ///< from rtsp.c, but used by rtp dynamic protocol handlers.
void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m);
const char *ff_rtp_enc_name(int payload_type);
enum CodecID ff_rtp_codec_id(const char *buf, enum CodecType codec_type);
void av_register_rtp_dynamic_payload_handlers(void);
// //
// Part of libavformat/rtsp.c
// //
#include <sys/time.h>
#include <unistd.h> /* for select() prototype */
//#define DEBUG
//#define DEBUG_RTP_TCP
enum RTSPClientState {
RTSP_STATE_IDLE,
RTSP_STATE_PLAYING,
@ -134,35 +222,10 @@ typedef struct RTSPState {
RTPDemuxContext *cur_rtp;
} RTSPState;
typedef struct RTSPStream {
URLContext *rtp_handle; /* RTP stream handle */
RTPDemuxContext *rtp_ctx; /* RTP parse context */
int stream_index; /* corresponding stream index, if any. -1 if none (MPEG2TS case) */
int interleaved_min, interleaved_max; /* interleave ids, if TCP transport */
char control_url[1024]; /* url for this stream (from SDP) */
int sdp_port; /* port (from SDP content - not used in RTSP) */
struct in_addr sdp_ip; /* IP address (from SDP content - not used in RTSP) */
int sdp_ttl; /* IP TTL (from SDP content - not used in RTSP) */
int sdp_payload_type; /* payload type - only used in SDP */
rtp_payload_data_t rtp_payload_data; /* rtp payload parsing infos from SDP */
RTPDynamicProtocolHandler *dynamic_handler; ///< Only valid if it's a dynamic protocol. (This is the handler structure)
void *dynamic_protocol_context; ///< Only valid if it's a dynamic protocol. (This is any private data associated with the dynamic protocol)
} RTSPStream;
extern "C"
{
int rtsp_next_attr_and_value(const char **p, char *attr, int attr_size, char *value, int value_size); ///< from rtsp.c, but used by rtp dynamic protocol handlers.
void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m);
const char *ff_rtp_enc_name(int payload_type);
enum CodecID ff_rtp_codec_id(const char *buf, enum CodecType codec_type);
void av_register_rtp_dynamic_payload_handlers(void);
}
//
// Declaration from libavformat/rtsp.c
//
int sdp_parse(AVFormatContext *s, const char *content);
#endif //ZM_SDP_H
#endif // ZM_SDP_H

View File

@ -22,6 +22,7 @@
#include "zm_debug.h"
#include "zm_utils.h"
#include <string.h>
#include <errno.h>
#include <sys/time.h>