Add support for H264 over RTP
Patch by Ryan Martell % rdm4 A martellventures P com % Original thread: Date: Oct 9, 2006 4:55 PM Subject: [Ffmpeg-devel] RTP patches & RFC Actual committed patch: Date: Oct 26, 2006 4:29 PM Originally committed as revision 6798 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
18fd519f54
commit
4934884a13
@ -416,6 +416,7 @@ void av_register_all(void)
|
|||||||
#ifdef CONFIG_REDIR_DEMUXER
|
#ifdef CONFIG_REDIR_DEMUXER
|
||||||
av_register_input_format(&redir_demuxer);
|
av_register_input_format(&redir_demuxer);
|
||||||
#endif
|
#endif
|
||||||
|
av_register_rtp_dynamic_payload_handlers();
|
||||||
#endif /* CONFIG_NETWORK */
|
#endif /* CONFIG_NETWORK */
|
||||||
#ifdef CONFIG_SEGAFILM_DEMUXER
|
#ifdef CONFIG_SEGAFILM_DEMUXER
|
||||||
av_register_input_format(&segafilm_demuxer);
|
av_register_input_format(&segafilm_demuxer);
|
||||||
|
@ -170,6 +170,9 @@ int pcm_read_seek(AVFormatContext *s,
|
|||||||
|
|
||||||
/* rtsp.c */
|
/* rtsp.c */
|
||||||
int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f);
|
int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f);
|
||||||
|
/* rtp.c */
|
||||||
|
void av_register_rtp_dynamic_payload_handlers();
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
extern AVImageFormat pnm_image_format;
|
extern AVImageFormat pnm_image_format;
|
||||||
|
@ -33,6 +33,13 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#include "rtp_internal.h"
|
||||||
|
|
||||||
|
//#define RTP_H264
|
||||||
|
#ifdef RTP_H264
|
||||||
|
#include "rtp_h264.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
|
|
||||||
|
|
||||||
@ -179,42 +186,26 @@ AVRtpPayloadType_t AVRtpPayloadTypes[]=
|
|||||||
{-1, "", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}
|
{-1, "", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
AVRtpDynamicPayloadType_t AVRtpDynamicPayloadTypes[]=
|
/* statistics functions */
|
||||||
|
RTPDynamicProtocolHandler *RTPFirstDynamicPayloadHandler= NULL;
|
||||||
|
|
||||||
|
static RTPDynamicProtocolHandler mp4v_es_handler= {"MP4V-ES", CODEC_TYPE_VIDEO, CODEC_ID_MPEG4};
|
||||||
|
static RTPDynamicProtocolHandler mpeg4_generic_handler= {"mpeg4-generic", CODEC_TYPE_AUDIO, CODEC_ID_MPEG4AAC};
|
||||||
|
|
||||||
|
static void register_dynamic_payload_handler(RTPDynamicProtocolHandler *handler)
|
||||||
{
|
{
|
||||||
{"MP4V-ES", CODEC_TYPE_VIDEO, CODEC_ID_MPEG4},
|
handler->next= RTPFirstDynamicPayloadHandler;
|
||||||
{"mpeg4-generic", CODEC_TYPE_AUDIO, CODEC_ID_MPEG4AAC},
|
RTPFirstDynamicPayloadHandler= handler;
|
||||||
{"", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
struct RTPDemuxContext {
|
void av_register_rtp_dynamic_payload_handlers()
|
||||||
AVFormatContext *ic;
|
{
|
||||||
AVStream *st;
|
register_dynamic_payload_handler(&mp4v_es_handler);
|
||||||
int payload_type;
|
register_dynamic_payload_handler(&mpeg4_generic_handler);
|
||||||
uint32_t ssrc;
|
#ifdef RTP_H264
|
||||||
uint16_t seq;
|
register_dynamic_payload_handler(&ff_h264_dynamic_handler);
|
||||||
uint32_t timestamp;
|
#endif
|
||||||
uint32_t base_timestamp;
|
}
|
||||||
uint32_t cur_timestamp;
|
|
||||||
int max_payload_size;
|
|
||||||
MpegTSContext *ts; /* only used for MP2T payloads */
|
|
||||||
int read_buf_index;
|
|
||||||
int read_buf_size;
|
|
||||||
|
|
||||||
/* rtcp sender statistics receive */
|
|
||||||
int64_t last_rtcp_ntp_time;
|
|
||||||
int64_t first_rtcp_ntp_time;
|
|
||||||
uint32_t last_rtcp_timestamp;
|
|
||||||
/* rtcp sender statistics */
|
|
||||||
unsigned int packet_count;
|
|
||||||
unsigned int octet_count;
|
|
||||||
unsigned int last_octet_count;
|
|
||||||
int first_packet;
|
|
||||||
/* buffer for output */
|
|
||||||
uint8_t buf[RTP_MAX_PACKET_LENGTH];
|
|
||||||
uint8_t *buf_ptr;
|
|
||||||
/* special infos for au headers parsing */
|
|
||||||
rtp_payload_data_t *rtp_payload_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
int rtp_get_codec_info(AVCodecContext *codec, int payload_type)
|
int rtp_get_codec_info(AVCodecContext *codec, int payload_type)
|
||||||
{
|
{
|
||||||
@ -271,6 +262,7 @@ static int rtcp_parse_packet(RTPDemuxContext *s, const unsigned char *buf, int l
|
|||||||
* open a new RTP parse context for stream 'st'. 'st' can be NULL for
|
* open a new RTP parse context for stream 'st'. 'st' can be NULL for
|
||||||
* MPEG2TS streams to indicate that they should be demuxed inside the
|
* MPEG2TS streams to indicate that they should be demuxed inside the
|
||||||
* rtp demux (otherwise CODEC_ID_MPEG2TS packets are returned)
|
* rtp demux (otherwise CODEC_ID_MPEG2TS packets are returned)
|
||||||
|
* TODO: change this to not take rtp_payload data, and use the new dynamic payload system.
|
||||||
*/
|
*/
|
||||||
RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_type, rtp_payload_data_t *rtp_payload_data)
|
RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_type, rtp_payload_data_t *rtp_payload_data)
|
||||||
{
|
{
|
||||||
@ -298,6 +290,9 @@ RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_t
|
|||||||
case CODEC_ID_MP2:
|
case CODEC_ID_MP2:
|
||||||
case CODEC_ID_MP3:
|
case CODEC_ID_MP3:
|
||||||
case CODEC_ID_MPEG4:
|
case CODEC_ID_MPEG4:
|
||||||
|
#ifdef RTP_H264
|
||||||
|
case CODEC_ID_H264:
|
||||||
|
#endif
|
||||||
st->need_parsing = 1;
|
st->need_parsing = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -374,6 +369,9 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
|
|||||||
|
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
/* return the next packets, if any */
|
/* return the next packets, if any */
|
||||||
|
if(s->st && s->parse_packet) {
|
||||||
|
return s->parse_packet(s, pkt, 0, NULL, 0);
|
||||||
|
} else {
|
||||||
if (s->read_buf_index >= s->read_buf_size)
|
if (s->read_buf_index >= s->read_buf_size)
|
||||||
return -1;
|
return -1;
|
||||||
ret = mpegts_parse_packet(s->ts, pkt, s->buf + s->read_buf_index,
|
ret = mpegts_parse_packet(s->ts, pkt, s->buf + s->read_buf_index,
|
||||||
@ -385,6 +383,7 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
|
|||||||
return 1;
|
return 1;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < 12)
|
if (len < 12)
|
||||||
@ -428,6 +427,7 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// at this point, the RTP header has been stripped; This is ASSUMING that there is only 1 CSRC, which in't wise.
|
||||||
switch(st->codec->codec_id) {
|
switch(st->codec->codec_id) {
|
||||||
case CODEC_ID_MP2:
|
case CODEC_ID_MP2:
|
||||||
/* better than nothing: skip mpeg audio RTP header */
|
/* better than nothing: skip mpeg audio RTP header */
|
||||||
@ -457,8 +457,12 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
|
|||||||
memcpy(pkt->data, buf, len);
|
memcpy(pkt->data, buf, len);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
if(s->parse_packet) {
|
||||||
|
return s->parse_packet(s, pkt, timestamp, buf, len);
|
||||||
|
} else {
|
||||||
av_new_packet(pkt, len);
|
av_new_packet(pkt, len);
|
||||||
memcpy(pkt->data, buf, len);
|
memcpy(pkt->data, buf, len);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,6 +515,7 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
|
|||||||
|
|
||||||
void rtp_parse_close(RTPDemuxContext *s)
|
void rtp_parse_close(RTPDemuxContext *s)
|
||||||
{
|
{
|
||||||
|
// TODO: fold this into the protocol specific data fields.
|
||||||
if (!strcmp(AVRtpPayloadTypes[s->payload_type].enc_name, "MP2T")) {
|
if (!strcmp(AVRtpPayloadTypes[s->payload_type].enc_name, "MP2T")) {
|
||||||
mpegts_parse_close(s->ts);
|
mpegts_parse_close(s->ts);
|
||||||
}
|
}
|
||||||
|
@ -89,13 +89,6 @@ typedef struct AVRtpPayloadType_s
|
|||||||
int audio_channels;
|
int audio_channels;
|
||||||
} AVRtpPayloadType_t;
|
} AVRtpPayloadType_t;
|
||||||
|
|
||||||
typedef struct AVRtpDynamicPayloadType_s /* payload type >= 96 */
|
|
||||||
{
|
|
||||||
const char enc_name[50]; /* XXX: still why 50 ? ;-) */
|
|
||||||
enum CodecType codec_type;
|
|
||||||
enum CodecID codec_id;
|
|
||||||
} AVRtpDynamicPayloadType_t;
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RTCP_SR = 200,
|
RTCP_SR = 200,
|
||||||
@ -122,6 +115,4 @@ typedef enum {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern AVRtpPayloadType_t AVRtpPayloadTypes[];
|
extern AVRtpPayloadType_t AVRtpPayloadTypes[];
|
||||||
extern AVRtpDynamicPayloadType_t AVRtpDynamicPayloadTypes[];
|
|
||||||
|
|
||||||
#endif /* RTP_H */
|
#endif /* RTP_H */
|
||||||
|
86
libavformat/rtp_internal.h
Normal file
86
libavformat/rtp_internal.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* RTP definitions
|
||||||
|
* Copyright (c) 2006 Ryan Martell <rdm4@martellventures.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
// this is a bit of a misnomer, because rtp & rtsp internal structures and prototypes are in here.
|
||||||
|
#ifndef RTP_INTERNAL_H
|
||||||
|
#define RTP_INTERNAL_H
|
||||||
|
|
||||||
|
typedef int (*DynamicPayloadPacketHandlerProc) (struct RTPDemuxContext * s,
|
||||||
|
AVPacket * pkt,
|
||||||
|
uint32_t timestamp,
|
||||||
|
const uint8_t * buf,
|
||||||
|
int len);
|
||||||
|
|
||||||
|
typedef struct RTPDynamicProtocolHandler_s {
|
||||||
|
// fields from AVRtpDynamicPayloadType_s
|
||||||
|
const char enc_name[50]; /* XXX: still why 50 ? ;-) */
|
||||||
|
enum CodecType codec_type;
|
||||||
|
enum CodecID codec_id;
|
||||||
|
|
||||||
|
// may be null
|
||||||
|
int (*parse_sdp_a_line) (AVStream * stream,
|
||||||
|
void *protocol_data,
|
||||||
|
const char *line); ///< Parse the a= line from the sdp field
|
||||||
|
void *(*open) (); ///< allocate any data needed by the rtp parsing for this dynamic data.
|
||||||
|
void (*close)(void *protocol_data); ///< free any data needed by the rtp parsing for this dynamic data.
|
||||||
|
DynamicPayloadPacketHandlerProc parse_packet; ///< parse handler for this dynamic packet.
|
||||||
|
|
||||||
|
struct RTPDynamicProtocolHandler_s *next;
|
||||||
|
} RTPDynamicProtocolHandler;
|
||||||
|
|
||||||
|
// moved out of rtp.c, because the h264 decoder needs to know about this structure..
|
||||||
|
struct RTPDemuxContext {
|
||||||
|
AVFormatContext *ic;
|
||||||
|
AVStream *st;
|
||||||
|
int payload_type;
|
||||||
|
uint32_t ssrc;
|
||||||
|
uint16_t seq;
|
||||||
|
uint32_t timestamp;
|
||||||
|
uint32_t base_timestamp;
|
||||||
|
uint32_t cur_timestamp;
|
||||||
|
int max_payload_size;
|
||||||
|
struct MpegTSContext *ts; /* only used for MP2T payloads */
|
||||||
|
int read_buf_index;
|
||||||
|
int read_buf_size;
|
||||||
|
|
||||||
|
/* rtcp sender statistics receive */
|
||||||
|
int64_t last_rtcp_ntp_time; // TODO: move into statistics
|
||||||
|
int64_t first_rtcp_ntp_time; // TODO: move into statistics
|
||||||
|
uint32_t last_rtcp_timestamp; // TODO: move into statistics
|
||||||
|
|
||||||
|
/* rtcp sender statistics */
|
||||||
|
unsigned int packet_count; // TODO: move into statistics (outgoing)
|
||||||
|
unsigned int octet_count; // TODO: move into statistics (outgoing)
|
||||||
|
unsigned int last_octet_count; // TODO: move into statistics (outgoing)
|
||||||
|
int first_packet;
|
||||||
|
/* buffer for output */
|
||||||
|
uint8_t buf[RTP_MAX_PACKET_LENGTH];
|
||||||
|
uint8_t *buf_ptr;
|
||||||
|
|
||||||
|
/* special infos for au headers parsing */
|
||||||
|
rtp_payload_data_t *rtp_payload_data; // TODO: Move into dynamic payload handlers
|
||||||
|
|
||||||
|
/* dynamic payload stuff */
|
||||||
|
DynamicPayloadPacketHandlerProc parse_packet; ///< This is also copied from the dynamic protocol handler structure
|
||||||
|
void *dynamic_protocol_context; ///< This is a copy from the values setup from the sdp parsing, in rtsp.c don't free me.
|
||||||
|
};
|
||||||
|
|
||||||
|
extern RTPDynamicProtocolHandler *RTPFirstDynamicPayloadHandler;
|
||||||
|
#endif /* RTP_INTERNAL_H */
|
||||||
|
|
@ -30,6 +30,8 @@
|
|||||||
# include "barpainet.h"
|
# include "barpainet.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "rtp_internal.h"
|
||||||
|
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
//#define DEBUG_RTP_TCP
|
//#define DEBUG_RTP_TCP
|
||||||
|
|
||||||
@ -69,6 +71,9 @@ typedef struct RTSPStream {
|
|||||||
int sdp_ttl; /* IP TTL (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 */
|
int sdp_payload_type; /* payload type - only used in SDP */
|
||||||
rtp_payload_data_t rtp_payload_data; /* rtp payload parsing infos from 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;
|
} RTSPStream;
|
||||||
|
|
||||||
static int rtsp_read_play(AVFormatContext *s);
|
static int rtsp_read_play(AVFormatContext *s);
|
||||||
@ -142,7 +147,7 @@ static void get_word(char *buf, int buf_size, const char **pp)
|
|||||||
|
|
||||||
/* parse the rtpmap description: <codec_name>/<clock_rate>[/<other
|
/* parse the rtpmap description: <codec_name>/<clock_rate>[/<other
|
||||||
params>] */
|
params>] */
|
||||||
static int sdp_parse_rtpmap(AVCodecContext *codec, int payload_type, const char *p)
|
static int sdp_parse_rtpmap(AVCodecContext *codec, RTSPStream *rtsp_st, int payload_type, const char *p)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int i;
|
int i;
|
||||||
@ -153,12 +158,18 @@ static int sdp_parse_rtpmap(AVCodecContext *codec, int payload_type, const char
|
|||||||
see if we can handle this kind of payload */
|
see if we can handle this kind of payload */
|
||||||
get_word_sep(buf, sizeof(buf), "/", &p);
|
get_word_sep(buf, sizeof(buf), "/", &p);
|
||||||
if (payload_type >= RTP_PT_PRIVATE) {
|
if (payload_type >= RTP_PT_PRIVATE) {
|
||||||
/* We are in dynmaic payload type case ... search into AVRtpDynamicPayloadTypes[] */
|
RTPDynamicProtocolHandler *handler= RTPFirstDynamicPayloadHandler;
|
||||||
for (i = 0; AVRtpDynamicPayloadTypes[i].codec_id != CODEC_ID_NONE; ++i)
|
while(handler) {
|
||||||
if (!strcmp(buf, AVRtpDynamicPayloadTypes[i].enc_name) && (codec->codec_type == AVRtpDynamicPayloadTypes[i].codec_type)) {
|
if (!strcmp(buf, handler->enc_name) && (codec->codec_type == handler->codec_type)) {
|
||||||
codec->codec_id = AVRtpDynamicPayloadTypes[i].codec_id;
|
codec->codec_id = handler->codec_id;
|
||||||
|
rtsp_st->dynamic_handler= handler;
|
||||||
|
if(handler->open) {
|
||||||
|
rtsp_st->dynamic_protocol_context= handler->open();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
handler= handler->next;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* We are in a standard case ( from http://www.iana.org/assignments/rtp-parameters) */
|
/* We are in a standard case ( from http://www.iana.org/assignments/rtp-parameters) */
|
||||||
/* search into AVRtpPayloadTypes[] */
|
/* search into AVRtpPayloadTypes[] */
|
||||||
@ -440,7 +451,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
|
|||||||
st = s->streams[i];
|
st = s->streams[i];
|
||||||
rtsp_st = st->priv_data;
|
rtsp_st = st->priv_data;
|
||||||
if (rtsp_st->sdp_payload_type == payload_type) {
|
if (rtsp_st->sdp_payload_type == payload_type) {
|
||||||
sdp_parse_rtpmap(st->codec, payload_type, p);
|
sdp_parse_rtpmap(st->codec, rtsp_st, payload_type, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (strstart(p, "fmtp:", &p)) {
|
} else if (strstart(p, "fmtp:", &p)) {
|
||||||
@ -451,7 +462,13 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
|
|||||||
st = s->streams[i];
|
st = s->streams[i];
|
||||||
rtsp_st = st->priv_data;
|
rtsp_st = st->priv_data;
|
||||||
if (rtsp_st->sdp_payload_type == payload_type) {
|
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)) {
|
||||||
|
sdp_parse_fmtp(st, p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
sdp_parse_fmtp(st, p);
|
sdp_parse_fmtp(st, p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -788,6 +805,8 @@ static void rtsp_close_streams(RTSPState *rt)
|
|||||||
rtp_parse_close(rtsp_st->rtp_ctx);
|
rtp_parse_close(rtsp_st->rtp_ctx);
|
||||||
if (rtsp_st->rtp_handle)
|
if (rtsp_st->rtp_handle)
|
||||||
url_close(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(rtsp_st);
|
av_free(rtsp_st);
|
||||||
}
|
}
|
||||||
@ -980,6 +999,11 @@ static int rtsp_read_header(AVFormatContext *s,
|
|||||||
if (!rtsp_st->rtp_ctx) {
|
if (!rtsp_st->rtp_ctx) {
|
||||||
err = AVERROR_NOMEM;
|
err = AVERROR_NOMEM;
|
||||||
goto fail;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1326,6 +1350,11 @@ static int sdp_read_header(AVFormatContext *s,
|
|||||||
if (!rtsp_st->rtp_ctx) {
|
if (!rtsp_st->rtp_ctx) {
|
||||||
err = AVERROR_NOMEM;
|
err = AVERROR_NOMEM;
|
||||||
goto fail;
|
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;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user