mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
Updates to payloader/depayloaders, make payloaders use the base classes.
Original commit message from CVS: Updates to payloader/depayloaders, make payloaders use the base classes. Updated README with suggested RTP caps and how to convert to/from SDP. Added config descriptor in mp4v payloader.
This commit is contained in:
parent
c7468729e9
commit
fc158bc3c2
37 changed files with 1066 additions and 2015 deletions
48
ChangeLog
48
ChangeLog
|
@ -1,3 +1,51 @@
|
||||||
|
2005-09-15 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* gst/rtp/Makefile.am:
|
||||||
|
* gst/rtp/README:
|
||||||
|
* gst/rtp/gstrtp.c: (plugin_init):
|
||||||
|
* gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_init),
|
||||||
|
(gst_rtpamrdec_sink_setcaps), (gst_rtpamrdec_chain),
|
||||||
|
(gst_rtpamrdec_change_state):
|
||||||
|
* gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_get_type),
|
||||||
|
(gst_rtpamrenc_class_init), (gst_rtpamrenc_init),
|
||||||
|
(gst_rtpamrenc_setcaps), (gst_rtpamrenc_handle_buffer):
|
||||||
|
* gst/rtp/gstrtpamrenc.h:
|
||||||
|
* gst/rtp/gstrtpgsmenc.c: (gst_rtpgsmenc_get_type),
|
||||||
|
(gst_rtpgsmenc_class_init), (gst_rtpgsmenc_init),
|
||||||
|
(gst_rtpgsmenc_setcaps), (gst_rtpgsmenc_handle_buffer):
|
||||||
|
* gst/rtp/gstrtpgsmenc.h:
|
||||||
|
* gst/rtp/gstrtpgsmparse.c: (gst_rtpgsmparse_class_init),
|
||||||
|
(gst_rtpgsm_caps_nego), (gst_rtpgsmparse_chain),
|
||||||
|
(gst_rtpgsmparse_set_property), (gst_rtpgsmparse_get_property),
|
||||||
|
(gst_rtpgsmparse_change_state):
|
||||||
|
* gst/rtp/gstrtpgsmparse.h:
|
||||||
|
* gst/rtp/gstrtph263pdec.c: (gst_rtph263pdec_class_init),
|
||||||
|
(gst_rtph263pdec_finalize), (gst_rtph263pdec_change_state):
|
||||||
|
* gst/rtp/gstrtph263penc.c: (gst_rtph263penc_get_type),
|
||||||
|
(gst_rtph263penc_class_init), (gst_rtph263penc_init),
|
||||||
|
(gst_rtph263penc_finalize), (gst_rtph263penc_setcaps),
|
||||||
|
(gst_rtph263penc_flush), (gst_rtph263penc_handle_buffer):
|
||||||
|
* gst/rtp/gstrtph263penc.h:
|
||||||
|
* gst/rtp/gstrtpmp4vdec.c: (gst_rtpmp4vdec_setcaps),
|
||||||
|
(gst_rtpmp4vdec_chain), (gst_rtpmp4vdec_change_state):
|
||||||
|
* gst/rtp/gstrtpmp4venc.c: (gst_rtpmp4venc_get_type),
|
||||||
|
(gst_rtpmp4venc_class_init), (gst_rtpmp4venc_init),
|
||||||
|
(gst_rtpmp4venc_finalize), (gst_rtpmp4venc_new_caps),
|
||||||
|
(gst_rtpmp4venc_setcaps), (gst_rtpmp4venc_flush),
|
||||||
|
(gst_rtpmp4venc_parse_data), (gst_rtpmp4venc_handle_buffer):
|
||||||
|
* gst/rtp/gstrtpmp4venc.h:
|
||||||
|
* gst/rtp/gstrtpmpadec.c:
|
||||||
|
* gst/rtp/gstrtpmpaenc.c: (gst_rtpmpaenc_get_type),
|
||||||
|
(gst_rtpmpaenc_class_init), (gst_rtpmpaenc_init),
|
||||||
|
(gst_rtpmpaenc_finalize), (gst_rtpmpaenc_setcaps),
|
||||||
|
(gst_rtpmpaenc_flush), (gst_rtpmpaenc_handle_buffer):
|
||||||
|
* gst/rtp/gstrtpmpaenc.h:
|
||||||
|
Updates to payloader/depayloaders, make payloaders use
|
||||||
|
the base classes.
|
||||||
|
Updated README with suggested RTP caps and how to convert
|
||||||
|
to/from SDP.
|
||||||
|
Added config descriptor in mp4v payloader.
|
||||||
|
|
||||||
2005-09-15 Andy Wingo <wingo@pobox.com>
|
2005-09-15 Andy Wingo <wingo@pobox.com>
|
||||||
|
|
||||||
* gst/autodetect/gstautoaudiosink.c (gst_auto_audio_sink_find_best):
|
* gst/autodetect/gstautoaudiosink.c (gst_auto_audio_sink_find_best):
|
||||||
|
|
2
common
2
common
|
@ -1 +1 @@
|
||||||
Subproject commit 97fbc2dd78ea0cc2225b63ff383802b7c376d9b7
|
Subproject commit 9a5025a2d276796d8d21243ef598e679ff7477bc
|
|
@ -4,6 +4,8 @@ libgstrtp_la_SOURCES = gstrtp.c \
|
||||||
gstrtpdec.c \
|
gstrtpdec.c \
|
||||||
gstrtpmpadec.c \
|
gstrtpmpadec.c \
|
||||||
gstrtpmpaenc.c \
|
gstrtpmpaenc.c \
|
||||||
|
gstrtpgsmenc.c \
|
||||||
|
gstrtpgsmparse.c \
|
||||||
gstrtpamrdec.c \
|
gstrtpamrdec.c \
|
||||||
gstrtpamrenc.c \
|
gstrtpamrenc.c \
|
||||||
gstrtph263pdec.c \
|
gstrtph263pdec.c \
|
||||||
|
|
|
@ -1,3 +1,70 @@
|
||||||
|
The application/x-rtp mime type
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
For valid RTP packets encapsulated in GstBuffers, we use the caps with
|
||||||
|
mime type application/x-rtp.
|
||||||
|
|
||||||
|
The following fields can or must (*) be specified in the structure:
|
||||||
|
|
||||||
|
* media: (String) [ "audio", "video", "application", "data", "control" ]
|
||||||
|
Defined in RFC 2327 in the SDP media announcement field.
|
||||||
|
|
||||||
|
* payload: (int) [0, 255]
|
||||||
|
For audio and video, these will normally be a media payload type as
|
||||||
|
defined in the RTP Audio/Video Profile. For dynamicaly allocated
|
||||||
|
payload types, this value will be >= 96 and the encoding_name must be
|
||||||
|
set.
|
||||||
|
|
||||||
|
* clock_rate: (int) [0 - MAXINT]
|
||||||
|
the RTP clock rate
|
||||||
|
|
||||||
|
ssrc: (uint) [0 - MAXINT]
|
||||||
|
The ssrc value currently in use.
|
||||||
|
|
||||||
|
clock_base: (uint) [0 - MAXINT]
|
||||||
|
The RTP time representing time 0
|
||||||
|
|
||||||
|
seqnum_base:
|
||||||
|
The RTP sequence number representing the first rtp packet
|
||||||
|
|
||||||
|
encoding_name: (String) ANY
|
||||||
|
typically second part of the mime type. ex. MP4V-ES. only required if
|
||||||
|
payload type >= 96
|
||||||
|
|
||||||
|
encoding_params: (String) ANY
|
||||||
|
extra encoding parameters (as in the SDP a=rtpmap: field). only required
|
||||||
|
if different from the default of the encoding_name.
|
||||||
|
|
||||||
|
Optional parameters as key/value pairs, media type specific.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
"application/x-rtp",
|
||||||
|
"media", G_TYPE_STRING, "audio", -]
|
||||||
|
"payload", G_TYPE_INT, 96, ] - required
|
||||||
|
"clock_rate", G_TYPE_INT, 8000, -]
|
||||||
|
"encoding_name", G_TYPE_STRING, "AMR", -] - required since payload >= 96
|
||||||
|
"encoding_params", G_TYPE_STRING, "1", -] - optional param for AMR
|
||||||
|
"octet-align", G_TYPE_BOOLEAN, TRUE, -]
|
||||||
|
"crc", G_TYPE_BOOLEAN, FALSE, ]
|
||||||
|
"robust-sorting", G_TYPE_BOOLEAN, FALSE, ] AMR specific params.
|
||||||
|
"interleaving", G_TYPE_BOOLEAN, FALSE, -]
|
||||||
|
|
||||||
|
Mapping of caps to and from SDP fields:
|
||||||
|
|
||||||
|
m=<media> <udp port> RTP/AVP <payload> -] media and payload from caps
|
||||||
|
a=rtpmap:<payload> <encoding_name>/<clock_rate>[/<encoding_params>]
|
||||||
|
-> when <payload> >= 96
|
||||||
|
a=fmtp:<payload> <param>=<value>;...
|
||||||
|
|
||||||
|
For above caps:
|
||||||
|
|
||||||
|
m=audio <udp port> RTP/AVP 96
|
||||||
|
a=rtpmap:96 AMR/8000/1
|
||||||
|
a=fmtp:96 octet-align=1;crc=0;robust-sorting=0;interleaving=0
|
||||||
|
|
||||||
|
in RTSP, the SSRC is also sent.
|
||||||
|
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
----
|
----
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstrtpdec.h"
|
#include "gstrtpdec.h"
|
||||||
|
#include "gstrtpgsmenc.h"
|
||||||
|
#include "gstrtpgsmparse.h"
|
||||||
#include "gstrtpamrenc.h"
|
#include "gstrtpamrenc.h"
|
||||||
#include "gstrtpamrdec.h"
|
#include "gstrtpamrdec.h"
|
||||||
#include "gstrtpmpaenc.h"
|
#include "gstrtpmpaenc.h"
|
||||||
|
@ -37,6 +39,12 @@ plugin_init (GstPlugin * plugin)
|
||||||
if (!gst_rtpdec_plugin_init (plugin))
|
if (!gst_rtpdec_plugin_init (plugin))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
if (!gst_rtpgsmparse_plugin_init (plugin))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!gst_rtpgsmenc_plugin_init (plugin))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (!gst_rtpamrdec_plugin_init (plugin))
|
if (!gst_rtpamrdec_plugin_init (plugin))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
static GstElementDetails gst_rtp_amrdec_details = {
|
static GstElementDetails gst_rtp_amrdec_details = {
|
||||||
"RTP packet parser",
|
"RTP packet parser",
|
||||||
"Codec/Parser/Network",
|
"Codec/Parser/Network",
|
||||||
"Extracts MPEG audio from RTP packets",
|
"Extracts AMR audio from RTP packets (RFC 3267)",
|
||||||
"Wim Taymans <wim@fluendo.com>"
|
"Wim Taymans <wim@fluendo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,11 +58,14 @@ GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp, "
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"audio\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 8000, "
|
||||||
|
"encoding_name = (string) \"AMR\", "
|
||||||
|
"encoding_params = (string) \"1\", "
|
||||||
"octet-align = (boolean) TRUE, "
|
"octet-align = (boolean) TRUE, "
|
||||||
"crc = (boolean) FALSE, "
|
"crc = (boolean) FALSE, "
|
||||||
"robust-sorting = (boolean) FALSE, "
|
"robust-sorting = (boolean) FALSE, " "interleaving = (boolean) FALSE"
|
||||||
"interleaving = (boolean) FALSE, "
|
|
||||||
"channels = (int) 1, " "rate = (int) 8000"
|
|
||||||
/* following options are not needed for a decoder
|
/* following options are not needed for a decoder
|
||||||
*
|
*
|
||||||
"mode-set = (int) [ 0, 7 ], "
|
"mode-set = (int) [ 0, 7 ], "
|
||||||
|
@ -156,18 +159,10 @@ gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec)
|
gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec)
|
||||||
{
|
{
|
||||||
GstCaps *srccaps;
|
|
||||||
|
|
||||||
rtpamrdec->srcpad =
|
rtpamrdec->srcpad =
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
gst_pad_new_from_template (gst_static_pad_template_get
|
||||||
(&gst_rtpamrdec_src_template), "src");
|
(&gst_rtpamrdec_src_template), "src");
|
||||||
|
|
||||||
/* FIXME */
|
|
||||||
srccaps = gst_caps_new_simple ("audio/AMR",
|
|
||||||
"channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
|
|
||||||
gst_pad_set_caps (rtpamrdec->srcpad, srccaps);
|
|
||||||
gst_caps_unref (srccaps);
|
|
||||||
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
|
gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
|
||||||
|
|
||||||
rtpamrdec->sinkpad =
|
rtpamrdec->sinkpad =
|
||||||
|
@ -184,6 +179,7 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
GstCaps *srccaps;
|
GstCaps *srccaps;
|
||||||
GstRtpAMRDec *rtpamrdec;
|
GstRtpAMRDec *rtpamrdec;
|
||||||
|
const gchar *params;
|
||||||
|
|
||||||
rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
|
rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
@ -193,10 +189,6 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
&rtpamrdec->octet_align))
|
&rtpamrdec->octet_align))
|
||||||
rtpamrdec->octet_align = FALSE;
|
rtpamrdec->octet_align = FALSE;
|
||||||
|
|
||||||
/* FIXME, force octect align for now until all elements negotiate
|
|
||||||
* correctly*/
|
|
||||||
rtpamrdec->octet_align = TRUE;
|
|
||||||
|
|
||||||
if (!gst_structure_get_boolean (structure, "crc", &rtpamrdec->crc))
|
if (!gst_structure_get_boolean (structure, "crc", &rtpamrdec->crc))
|
||||||
rtpamrdec->crc = FALSE;
|
rtpamrdec->crc = FALSE;
|
||||||
|
|
||||||
|
@ -223,9 +215,13 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
rtpamrdec->octet_align = TRUE;
|
rtpamrdec->octet_align = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gst_structure_get_int (structure, "channels", &rtpamrdec->channels))
|
if (!(params = gst_structure_get_string (structure, "encoding_params")))
|
||||||
rtpamrdec->channels = 1;
|
rtpamrdec->channels = 1;
|
||||||
if (!gst_structure_get_int (structure, "rate", &rtpamrdec->rate))
|
else {
|
||||||
|
rtpamrdec->channels = atoi (params);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_structure_get_int (structure, "clock_rate", &rtpamrdec->rate))
|
||||||
rtpamrdec->rate = 8000;
|
rtpamrdec->rate = 8000;
|
||||||
|
|
||||||
/* we require 1 channel, 8000 Hz, octet aligned, no CRC,
|
/* we require 1 channel, 8000 Hz, octet aligned, no CRC,
|
||||||
|
@ -288,7 +284,7 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
/* parse header
|
/* parse header
|
||||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
|
||||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
|
||||||
* | CMR=6 |R|R|R|R|0|FT#1=5 |Q|P|P|
|
* | CMR |R|R|R|R|F| FT |Q|P|P|
|
||||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
|
||||||
*/
|
*/
|
||||||
CMR = (payload[0] & 0xf0) >> 4;
|
CMR = (payload[0] & 0xf0) >> 4;
|
||||||
|
@ -314,7 +310,7 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
|
|
||||||
outbuf = gst_buffer_new_and_alloc (payload_len);
|
outbuf = gst_buffer_new_and_alloc (payload_len);
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 8000;
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / rtpamrdec->rate;
|
||||||
|
|
||||||
memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
|
memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
|
||||||
|
|
||||||
|
@ -392,9 +388,6 @@ gst_rtpamrdec_change_state (GstElement * element, GstStateChange transition)
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
/* FIXME, don't require negotiation until all elements
|
|
||||||
* do */
|
|
||||||
rtpamrdec->negotiated = TRUE;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
static GstElementDetails gst_rtp_amrdec_details = {
|
static GstElementDetails gst_rtp_amrdec_details = {
|
||||||
"RTP packet parser",
|
"RTP packet parser",
|
||||||
"Codec/Parser/Network",
|
"Codec/Parser/Network",
|
||||||
"Extracts MPEG audio from RTP packets",
|
"Extracts AMR audio from RTP packets (RFC 3267)",
|
||||||
"Wim Taymans <wim@fluendo.com>"
|
"Wim Taymans <wim@fluendo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,11 +58,14 @@ GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp, "
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"audio\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 8000, "
|
||||||
|
"encoding_name = (string) \"AMR\", "
|
||||||
|
"encoding_params = (string) \"1\", "
|
||||||
"octet-align = (boolean) TRUE, "
|
"octet-align = (boolean) TRUE, "
|
||||||
"crc = (boolean) FALSE, "
|
"crc = (boolean) FALSE, "
|
||||||
"robust-sorting = (boolean) FALSE, "
|
"robust-sorting = (boolean) FALSE, " "interleaving = (boolean) FALSE"
|
||||||
"interleaving = (boolean) FALSE, "
|
|
||||||
"channels = (int) 1, " "rate = (int) 8000"
|
|
||||||
/* following options are not needed for a decoder
|
/* following options are not needed for a decoder
|
||||||
*
|
*
|
||||||
"mode-set = (int) [ 0, 7 ], "
|
"mode-set = (int) [ 0, 7 ], "
|
||||||
|
@ -156,18 +159,10 @@ gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec)
|
gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec)
|
||||||
{
|
{
|
||||||
GstCaps *srccaps;
|
|
||||||
|
|
||||||
rtpamrdec->srcpad =
|
rtpamrdec->srcpad =
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
gst_pad_new_from_template (gst_static_pad_template_get
|
||||||
(&gst_rtpamrdec_src_template), "src");
|
(&gst_rtpamrdec_src_template), "src");
|
||||||
|
|
||||||
/* FIXME */
|
|
||||||
srccaps = gst_caps_new_simple ("audio/AMR",
|
|
||||||
"channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
|
|
||||||
gst_pad_set_caps (rtpamrdec->srcpad, srccaps);
|
|
||||||
gst_caps_unref (srccaps);
|
|
||||||
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
|
gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
|
||||||
|
|
||||||
rtpamrdec->sinkpad =
|
rtpamrdec->sinkpad =
|
||||||
|
@ -184,6 +179,7 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
GstCaps *srccaps;
|
GstCaps *srccaps;
|
||||||
GstRtpAMRDec *rtpamrdec;
|
GstRtpAMRDec *rtpamrdec;
|
||||||
|
const gchar *params;
|
||||||
|
|
||||||
rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
|
rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
@ -193,10 +189,6 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
&rtpamrdec->octet_align))
|
&rtpamrdec->octet_align))
|
||||||
rtpamrdec->octet_align = FALSE;
|
rtpamrdec->octet_align = FALSE;
|
||||||
|
|
||||||
/* FIXME, force octect align for now until all elements negotiate
|
|
||||||
* correctly*/
|
|
||||||
rtpamrdec->octet_align = TRUE;
|
|
||||||
|
|
||||||
if (!gst_structure_get_boolean (structure, "crc", &rtpamrdec->crc))
|
if (!gst_structure_get_boolean (structure, "crc", &rtpamrdec->crc))
|
||||||
rtpamrdec->crc = FALSE;
|
rtpamrdec->crc = FALSE;
|
||||||
|
|
||||||
|
@ -223,9 +215,13 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
rtpamrdec->octet_align = TRUE;
|
rtpamrdec->octet_align = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gst_structure_get_int (structure, "channels", &rtpamrdec->channels))
|
if (!(params = gst_structure_get_string (structure, "encoding_params")))
|
||||||
rtpamrdec->channels = 1;
|
rtpamrdec->channels = 1;
|
||||||
if (!gst_structure_get_int (structure, "rate", &rtpamrdec->rate))
|
else {
|
||||||
|
rtpamrdec->channels = atoi (params);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_structure_get_int (structure, "clock_rate", &rtpamrdec->rate))
|
||||||
rtpamrdec->rate = 8000;
|
rtpamrdec->rate = 8000;
|
||||||
|
|
||||||
/* we require 1 channel, 8000 Hz, octet aligned, no CRC,
|
/* we require 1 channel, 8000 Hz, octet aligned, no CRC,
|
||||||
|
@ -288,7 +284,7 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
/* parse header
|
/* parse header
|
||||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
|
||||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
|
||||||
* | CMR=6 |R|R|R|R|0|FT#1=5 |Q|P|P|
|
* | CMR |R|R|R|R|F| FT |Q|P|P|
|
||||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
|
||||||
*/
|
*/
|
||||||
CMR = (payload[0] & 0xf0) >> 4;
|
CMR = (payload[0] & 0xf0) >> 4;
|
||||||
|
@ -314,7 +310,7 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
|
|
||||||
outbuf = gst_buffer_new_and_alloc (payload_len);
|
outbuf = gst_buffer_new_and_alloc (payload_len);
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 8000;
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / rtpamrdec->rate;
|
||||||
|
|
||||||
memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
|
memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
|
||||||
|
|
||||||
|
@ -392,9 +388,6 @@ gst_rtpamrdec_change_state (GstElement * element, GstStateChange transition)
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
/* FIXME, don't require negotiation until all elements
|
|
||||||
* do */
|
|
||||||
rtpamrdec->negotiated = TRUE;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -33,29 +33,10 @@
|
||||||
static GstElementDetails gst_rtp_amrenc_details = {
|
static GstElementDetails gst_rtp_amrenc_details = {
|
||||||
"RTP packet parser",
|
"RTP packet parser",
|
||||||
"Codec/Parser/Network",
|
"Codec/Parser/Network",
|
||||||
"Encode AMR audio into RTP packets",
|
"Encode AMR audio into RTP packets (RFC 3267)",
|
||||||
"Wim Taymans <wim@fluendo.com>"
|
"Wim Taymans <wim@fluendo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RtpAMREnc signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DEFAULT_MTU 1024
|
|
||||||
#define DEFAULT_PT 96
|
|
||||||
#define DEFAULT_SSRC 0
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_MTU,
|
|
||||||
PROP_PT,
|
|
||||||
PROP_SSRC
|
|
||||||
};
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtpamrenc_sink_template =
|
static GstStaticPadTemplate gst_rtpamrenc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -68,34 +49,31 @@ GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp, "
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"audio\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 8000, "
|
||||||
|
"encoding_name = (string) \"AMR\", "
|
||||||
|
"encoding_params = (string) \"1\", "
|
||||||
"octet-align = (boolean) TRUE, "
|
"octet-align = (boolean) TRUE, "
|
||||||
"crc = (boolean) FALSE, "
|
"crc = (boolean) FALSE, "
|
||||||
"robust-sorting = (boolean) FALSE, "
|
"robust-sorting = (boolean) FALSE, "
|
||||||
"interleaving = (boolean) FALSE, "
|
"interleaving = (boolean) FALSE, "
|
||||||
"channels = (int) 1, "
|
|
||||||
"rate = (int) 8000, "
|
|
||||||
"mode-set = (int) [ 0, 7 ], "
|
"mode-set = (int) [ 0, 7 ], "
|
||||||
"mode-change-period = (int) [ 1, MAX ], "
|
"mode-change-period = (int) [ 1, MAX ], "
|
||||||
"mode-change-neighbor = (boolean) { TRUE, FALSE }, "
|
"mode-change-neighbor = (boolean) { TRUE, FALSE }, "
|
||||||
"maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
|
"maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void gst_rtpamrenc_class_init (GstRtpAMREncClass * klass);
|
static void gst_rtpamrenc_class_init (GstRtpAMREncClass * klass);
|
||||||
static void gst_rtpamrenc_base_init (GstRtpAMREncClass * klass);
|
static void gst_rtpamrenc_base_init (GstRtpAMREncClass * klass);
|
||||||
static void gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc);
|
static void gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc);
|
||||||
|
|
||||||
static GstFlowReturn gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer);
|
static gboolean gst_rtpamrenc_setcaps (GstBaseRTPPayload * basepayload,
|
||||||
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_rtpamrenc_handle_buffer (GstBaseRTPPayload * pad,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
static void gst_rtpamrenc_set_property (GObject * object, guint prop_id,
|
static GstBaseRTPPayloadClass *parent_class = NULL;
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_rtpamrenc_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
|
|
||||||
static GstStateChangeReturn gst_rtpamrenc_change_state (GstElement * element,
|
|
||||||
GstStateChange transition);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gst_rtpamrenc_get_type (void)
|
gst_rtpamrenc_get_type (void)
|
||||||
|
@ -116,7 +94,7 @@ gst_rtpamrenc_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
rtpamrenc_type =
|
rtpamrenc_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRtpAMREnc",
|
g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpAMREnc",
|
||||||
&rtpamrenc_info, 0);
|
&rtpamrenc_info, 0);
|
||||||
}
|
}
|
||||||
return rtpamrenc_type;
|
return rtpamrenc_type;
|
||||||
|
@ -140,64 +118,44 @@ gst_rtpamrenc_class_init (GstRtpAMREncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtpamrenc_set_property;
|
gstbasertppayload_class->set_caps = gst_rtpamrenc_setcaps;
|
||||||
gobject_class->get_property = gst_rtpamrenc_get_property;
|
gstbasertppayload_class->handle_buffer = gst_rtpamrenc_handle_buffer;
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
|
|
||||||
g_param_spec_uint ("mtu", "MTU",
|
|
||||||
"Maximum size of one packet",
|
|
||||||
28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
|
|
||||||
g_param_spec_uint ("pt", "payload type",
|
|
||||||
"The payload type of the packets",
|
|
||||||
0, 0x80, DEFAULT_PT, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
|
|
||||||
g_param_spec_uint ("ssrc", "SSRC",
|
|
||||||
"The SSRC of the packets",
|
|
||||||
0, G_MAXUINT, DEFAULT_SSRC, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtpamrenc_change_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc)
|
gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc)
|
||||||
{
|
{
|
||||||
GstCaps *caps;
|
}
|
||||||
|
|
||||||
rtpamrenc->srcpad =
|
static gboolean
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
gst_rtpamrenc_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
|
||||||
(&gst_rtpamrenc_src_template), "src");
|
{
|
||||||
|
GstRtpAMREnc *rtpamrenc;
|
||||||
|
|
||||||
caps = gst_caps_new_simple ("application/x-rtp",
|
rtpamrenc = GST_RTP_AMR_ENC (basepayload);
|
||||||
|
|
||||||
|
gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
|
||||||
|
gst_basertppayload_set_outcaps (basepayload,
|
||||||
|
"encoding_params", G_TYPE_STRING, "1",
|
||||||
"octet-align", G_TYPE_BOOLEAN, TRUE,
|
"octet-align", G_TYPE_BOOLEAN, TRUE,
|
||||||
"crc", G_TYPE_BOOLEAN, FALSE,
|
"crc", G_TYPE_BOOLEAN, FALSE,
|
||||||
"robust-sorting", G_TYPE_BOOLEAN, FALSE,
|
"robust-sorting", G_TYPE_BOOLEAN, FALSE,
|
||||||
"interleaving", G_TYPE_BOOLEAN, FALSE,
|
"interleaving", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
"channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
|
|
||||||
|
|
||||||
gst_pad_set_caps (rtpamrenc->srcpad, caps);
|
return TRUE;
|
||||||
gst_caps_unref (caps);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpamrenc), rtpamrenc->srcpad);
|
|
||||||
|
|
||||||
rtpamrenc->sinkpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpamrenc_sink_template), "sink");
|
|
||||||
gst_pad_set_chain_function (rtpamrenc->sinkpad, gst_rtpamrenc_chain);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpamrenc), rtpamrenc->sinkpad);
|
|
||||||
|
|
||||||
rtpamrenc->mtu = DEFAULT_MTU;
|
|
||||||
rtpamrenc->pt = DEFAULT_PT;
|
|
||||||
rtpamrenc->ssrc = DEFAULT_SSRC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
|
gst_rtpamrenc_handle_buffer (GstBaseRTPPayload * basepayload,
|
||||||
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstRtpAMREnc *rtpamrenc;
|
GstRtpAMREnc *rtpamrenc;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
@ -206,7 +164,7 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
guint8 *payload, *data;
|
guint8 *payload, *data;
|
||||||
GstClockTime timestamp;
|
GstClockTime timestamp;
|
||||||
|
|
||||||
rtpamrenc = GST_RTP_AMR_ENC (gst_pad_get_parent (pad));
|
rtpamrenc = GST_RTP_AMR_ENC (basepayload);
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (buffer);
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
@ -221,12 +179,7 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
||||||
/* FIXME, assert for now */
|
/* FIXME, assert for now */
|
||||||
g_assert (GST_BUFFER_SIZE (outbuf) < rtpamrenc->mtu);
|
g_assert (GST_BUFFER_SIZE (outbuf) < GST_BASE_RTP_PAYLOAD_MTU (rtpamrenc));
|
||||||
|
|
||||||
gst_rtpbuffer_set_payload_type (outbuf, rtpamrenc->pt);
|
|
||||||
gst_rtpbuffer_set_ssrc (outbuf, rtpamrenc->ssrc);
|
|
||||||
gst_rtpbuffer_set_seq (outbuf, rtpamrenc->seqnum++);
|
|
||||||
gst_rtpbuffer_set_timestamp (outbuf, timestamp * 8000 / GST_SECOND);
|
|
||||||
|
|
||||||
/* copy timestamp */
|
/* copy timestamp */
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
||||||
|
@ -256,89 +209,8 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrenc->srcpad));
|
ret = gst_basertppayload_push (basepayload, outbuf);
|
||||||
|
|
||||||
ret = gst_pad_push (rtpamrenc->srcpad, outbuf);
|
|
||||||
|
|
||||||
gst_object_unref (rtpamrenc);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpamrenc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpAMREnc *rtpamrenc;
|
|
||||||
|
|
||||||
rtpamrenc = GST_RTP_AMR_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
rtpamrenc->mtu = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
rtpamrenc->pt = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
rtpamrenc->ssrc = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpamrenc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpAMREnc *rtpamrenc;
|
|
||||||
|
|
||||||
rtpamrenc = GST_RTP_AMR_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
g_value_set_uint (value, rtpamrenc->mtu);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
g_value_set_uint (value, rtpamrenc->pt);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
g_value_set_uint (value, rtpamrenc->ssrc);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_rtpamrenc_change_state (GstElement * element, GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstRtpAMREnc *rtpamrenc;
|
|
||||||
GstStateChangeReturn ret;
|
|
||||||
|
|
||||||
rtpamrenc = GST_RTP_AMR_ENC (element);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
||||||
rtpamrenc->seqnum = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define __GST_RTP_AMR_ENC_H__
|
#define __GST_RTP_AMR_ENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/rtp/gstbasertppayload.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -41,21 +42,12 @@ typedef struct _GstRtpAMREncClass GstRtpAMREncClass;
|
||||||
|
|
||||||
struct _GstRtpAMREnc
|
struct _GstRtpAMREnc
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstBaseRTPPayload payload;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
guint16 seqnum;
|
|
||||||
guint pt;
|
|
||||||
guint ssrc;
|
|
||||||
|
|
||||||
guint mtu;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstRtpAMREncClass
|
struct _GstRtpAMREncClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstBaseRTPPayloadClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
gboolean gst_rtpamrenc_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtpamrenc_plugin_init (GstPlugin * plugin);
|
||||||
|
|
|
@ -33,29 +33,10 @@
|
||||||
static GstElementDetails gst_rtp_amrenc_details = {
|
static GstElementDetails gst_rtp_amrenc_details = {
|
||||||
"RTP packet parser",
|
"RTP packet parser",
|
||||||
"Codec/Parser/Network",
|
"Codec/Parser/Network",
|
||||||
"Encode AMR audio into RTP packets",
|
"Encode AMR audio into RTP packets (RFC 3267)",
|
||||||
"Wim Taymans <wim@fluendo.com>"
|
"Wim Taymans <wim@fluendo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RtpAMREnc signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DEFAULT_MTU 1024
|
|
||||||
#define DEFAULT_PT 96
|
|
||||||
#define DEFAULT_SSRC 0
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_MTU,
|
|
||||||
PROP_PT,
|
|
||||||
PROP_SSRC
|
|
||||||
};
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtpamrenc_sink_template =
|
static GstStaticPadTemplate gst_rtpamrenc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -68,34 +49,31 @@ GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp, "
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"audio\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 8000, "
|
||||||
|
"encoding_name = (string) \"AMR\", "
|
||||||
|
"encoding_params = (string) \"1\", "
|
||||||
"octet-align = (boolean) TRUE, "
|
"octet-align = (boolean) TRUE, "
|
||||||
"crc = (boolean) FALSE, "
|
"crc = (boolean) FALSE, "
|
||||||
"robust-sorting = (boolean) FALSE, "
|
"robust-sorting = (boolean) FALSE, "
|
||||||
"interleaving = (boolean) FALSE, "
|
"interleaving = (boolean) FALSE, "
|
||||||
"channels = (int) 1, "
|
|
||||||
"rate = (int) 8000, "
|
|
||||||
"mode-set = (int) [ 0, 7 ], "
|
"mode-set = (int) [ 0, 7 ], "
|
||||||
"mode-change-period = (int) [ 1, MAX ], "
|
"mode-change-period = (int) [ 1, MAX ], "
|
||||||
"mode-change-neighbor = (boolean) { TRUE, FALSE }, "
|
"mode-change-neighbor = (boolean) { TRUE, FALSE }, "
|
||||||
"maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
|
"maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void gst_rtpamrenc_class_init (GstRtpAMREncClass * klass);
|
static void gst_rtpamrenc_class_init (GstRtpAMREncClass * klass);
|
||||||
static void gst_rtpamrenc_base_init (GstRtpAMREncClass * klass);
|
static void gst_rtpamrenc_base_init (GstRtpAMREncClass * klass);
|
||||||
static void gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc);
|
static void gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc);
|
||||||
|
|
||||||
static GstFlowReturn gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer);
|
static gboolean gst_rtpamrenc_setcaps (GstBaseRTPPayload * basepayload,
|
||||||
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_rtpamrenc_handle_buffer (GstBaseRTPPayload * pad,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
static void gst_rtpamrenc_set_property (GObject * object, guint prop_id,
|
static GstBaseRTPPayloadClass *parent_class = NULL;
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_rtpamrenc_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
|
|
||||||
static GstStateChangeReturn gst_rtpamrenc_change_state (GstElement * element,
|
|
||||||
GstStateChange transition);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gst_rtpamrenc_get_type (void)
|
gst_rtpamrenc_get_type (void)
|
||||||
|
@ -116,7 +94,7 @@ gst_rtpamrenc_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
rtpamrenc_type =
|
rtpamrenc_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRtpAMREnc",
|
g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpAMREnc",
|
||||||
&rtpamrenc_info, 0);
|
&rtpamrenc_info, 0);
|
||||||
}
|
}
|
||||||
return rtpamrenc_type;
|
return rtpamrenc_type;
|
||||||
|
@ -140,64 +118,44 @@ gst_rtpamrenc_class_init (GstRtpAMREncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtpamrenc_set_property;
|
gstbasertppayload_class->set_caps = gst_rtpamrenc_setcaps;
|
||||||
gobject_class->get_property = gst_rtpamrenc_get_property;
|
gstbasertppayload_class->handle_buffer = gst_rtpamrenc_handle_buffer;
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
|
|
||||||
g_param_spec_uint ("mtu", "MTU",
|
|
||||||
"Maximum size of one packet",
|
|
||||||
28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
|
|
||||||
g_param_spec_uint ("pt", "payload type",
|
|
||||||
"The payload type of the packets",
|
|
||||||
0, 0x80, DEFAULT_PT, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
|
|
||||||
g_param_spec_uint ("ssrc", "SSRC",
|
|
||||||
"The SSRC of the packets",
|
|
||||||
0, G_MAXUINT, DEFAULT_SSRC, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtpamrenc_change_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc)
|
gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc)
|
||||||
{
|
{
|
||||||
GstCaps *caps;
|
}
|
||||||
|
|
||||||
rtpamrenc->srcpad =
|
static gboolean
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
gst_rtpamrenc_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
|
||||||
(&gst_rtpamrenc_src_template), "src");
|
{
|
||||||
|
GstRtpAMREnc *rtpamrenc;
|
||||||
|
|
||||||
caps = gst_caps_new_simple ("application/x-rtp",
|
rtpamrenc = GST_RTP_AMR_ENC (basepayload);
|
||||||
|
|
||||||
|
gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
|
||||||
|
gst_basertppayload_set_outcaps (basepayload,
|
||||||
|
"encoding_params", G_TYPE_STRING, "1",
|
||||||
"octet-align", G_TYPE_BOOLEAN, TRUE,
|
"octet-align", G_TYPE_BOOLEAN, TRUE,
|
||||||
"crc", G_TYPE_BOOLEAN, FALSE,
|
"crc", G_TYPE_BOOLEAN, FALSE,
|
||||||
"robust-sorting", G_TYPE_BOOLEAN, FALSE,
|
"robust-sorting", G_TYPE_BOOLEAN, FALSE,
|
||||||
"interleaving", G_TYPE_BOOLEAN, FALSE,
|
"interleaving", G_TYPE_BOOLEAN, FALSE, NULL);
|
||||||
"channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
|
|
||||||
|
|
||||||
gst_pad_set_caps (rtpamrenc->srcpad, caps);
|
return TRUE;
|
||||||
gst_caps_unref (caps);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpamrenc), rtpamrenc->srcpad);
|
|
||||||
|
|
||||||
rtpamrenc->sinkpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpamrenc_sink_template), "sink");
|
|
||||||
gst_pad_set_chain_function (rtpamrenc->sinkpad, gst_rtpamrenc_chain);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpamrenc), rtpamrenc->sinkpad);
|
|
||||||
|
|
||||||
rtpamrenc->mtu = DEFAULT_MTU;
|
|
||||||
rtpamrenc->pt = DEFAULT_PT;
|
|
||||||
rtpamrenc->ssrc = DEFAULT_SSRC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
|
gst_rtpamrenc_handle_buffer (GstBaseRTPPayload * basepayload,
|
||||||
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstRtpAMREnc *rtpamrenc;
|
GstRtpAMREnc *rtpamrenc;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
@ -206,7 +164,7 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
guint8 *payload, *data;
|
guint8 *payload, *data;
|
||||||
GstClockTime timestamp;
|
GstClockTime timestamp;
|
||||||
|
|
||||||
rtpamrenc = GST_RTP_AMR_ENC (gst_pad_get_parent (pad));
|
rtpamrenc = GST_RTP_AMR_ENC (basepayload);
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (buffer);
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
@ -221,12 +179,7 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
||||||
/* FIXME, assert for now */
|
/* FIXME, assert for now */
|
||||||
g_assert (GST_BUFFER_SIZE (outbuf) < rtpamrenc->mtu);
|
g_assert (GST_BUFFER_SIZE (outbuf) < GST_BASE_RTP_PAYLOAD_MTU (rtpamrenc));
|
||||||
|
|
||||||
gst_rtpbuffer_set_payload_type (outbuf, rtpamrenc->pt);
|
|
||||||
gst_rtpbuffer_set_ssrc (outbuf, rtpamrenc->ssrc);
|
|
||||||
gst_rtpbuffer_set_seq (outbuf, rtpamrenc->seqnum++);
|
|
||||||
gst_rtpbuffer_set_timestamp (outbuf, timestamp * 8000 / GST_SECOND);
|
|
||||||
|
|
||||||
/* copy timestamp */
|
/* copy timestamp */
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
||||||
|
@ -256,89 +209,8 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrenc->srcpad));
|
ret = gst_basertppayload_push (basepayload, outbuf);
|
||||||
|
|
||||||
ret = gst_pad_push (rtpamrenc->srcpad, outbuf);
|
|
||||||
|
|
||||||
gst_object_unref (rtpamrenc);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpamrenc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpAMREnc *rtpamrenc;
|
|
||||||
|
|
||||||
rtpamrenc = GST_RTP_AMR_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
rtpamrenc->mtu = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
rtpamrenc->pt = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
rtpamrenc->ssrc = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpamrenc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpAMREnc *rtpamrenc;
|
|
||||||
|
|
||||||
rtpamrenc = GST_RTP_AMR_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
g_value_set_uint (value, rtpamrenc->mtu);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
g_value_set_uint (value, rtpamrenc->pt);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
g_value_set_uint (value, rtpamrenc->ssrc);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_rtpamrenc_change_state (GstElement * element, GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstRtpAMREnc *rtpamrenc;
|
|
||||||
GstStateChangeReturn ret;
|
|
||||||
|
|
||||||
rtpamrenc = GST_RTP_AMR_ENC (element);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
||||||
rtpamrenc->seqnum = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define __GST_RTP_AMR_ENC_H__
|
#define __GST_RTP_AMR_ENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/rtp/gstbasertppayload.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -41,21 +42,12 @@ typedef struct _GstRtpAMREncClass GstRtpAMREncClass;
|
||||||
|
|
||||||
struct _GstRtpAMREnc
|
struct _GstRtpAMREnc
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstBaseRTPPayload payload;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
guint16 seqnum;
|
|
||||||
guint pt;
|
|
||||||
guint ssrc;
|
|
||||||
|
|
||||||
guint mtu;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstRtpAMREncClass
|
struct _GstRtpAMREncClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstBaseRTPPayloadClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
gboolean gst_rtpamrenc_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtpamrenc_plugin_init (GstPlugin * plugin);
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <gst/rtp/gstrtpbuffer.h>
|
||||||
#include "gstrtpgsmparse.h"
|
#include "gstrtpgsmparse.h"
|
||||||
#include "gstrtp-common.h"
|
|
||||||
|
|
||||||
/* elementfactory information */
|
/* elementfactory information */
|
||||||
static GstElementDetails gst_rtp_gsmparse_details = {
|
static GstElementDetails gst_rtp_gsmparse_details = {
|
||||||
|
@ -60,13 +60,15 @@ static void gst_rtpgsmparse_class_init (GstRtpGSMParseClass * klass);
|
||||||
static void gst_rtpgsmparse_base_init (GstRtpGSMParseClass * klass);
|
static void gst_rtpgsmparse_base_init (GstRtpGSMParseClass * klass);
|
||||||
static void gst_rtpgsmparse_init (GstRtpGSMParse * rtpgsmparse);
|
static void gst_rtpgsmparse_init (GstRtpGSMParse * rtpgsmparse);
|
||||||
|
|
||||||
static void gst_rtpgsmparse_chain (GstPad * pad, GstData * _data);
|
static GstFlowReturn gst_rtpgsmparse_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
|
|
||||||
static void gst_rtpgsmparse_set_property (GObject * object, guint prop_id,
|
static void gst_rtpgsmparse_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
static void gst_rtpgsmparse_get_property (GObject * object, guint prop_id,
|
static void gst_rtpgsmparse_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
static GstStateChangeReturn gst_rtpgsmparse_change_state (GstElement * element);
|
|
||||||
|
static GstStateChangeReturn gst_rtpgsmparse_change_state (GstElement * element,
|
||||||
|
GstStateChange transition);
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
static GstElementClass *parent_class = NULL;
|
||||||
|
|
||||||
|
@ -118,13 +120,13 @@ gst_rtpgsmparse_class_init (GstRtpGSMParseClass * klass)
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
|
gobject_class->set_property = gst_rtpgsmparse_set_property;
|
||||||
|
gobject_class->get_property = gst_rtpgsmparse_get_property;
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FREQUENCY,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FREQUENCY,
|
||||||
g_param_spec_int ("frequency", "frequency", "frequency",
|
g_param_spec_int ("frequency", "frequency", "frequency",
|
||||||
G_MININT, G_MAXINT, 8000, G_PARAM_READWRITE));
|
G_MININT, G_MAXINT, 8000, G_PARAM_READWRITE));
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtpgsmparse_set_property;
|
|
||||||
gobject_class->get_property = gst_rtpgsmparse_get_property;
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtpgsmparse_change_state;
|
gstelement_class->change_state = gst_rtpgsmparse_change_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,21 +146,7 @@ gst_rtpgsmparse_init (GstRtpGSMParse * rtpgsmparse)
|
||||||
rtpgsmparse->frequency = 8000;
|
rtpgsmparse->frequency = 8000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
gst_rtpgsmparse_ntohs (GstBuffer * buf)
|
|
||||||
{
|
|
||||||
gint16 *i, *len;
|
|
||||||
|
|
||||||
/* FIXME: is this code correct or even sane at all? */
|
|
||||||
i = (gint16 *) GST_BUFFER_DATA (buf);
|
|
||||||
len = i + GST_BUFFER_SIZE (buf) / sizeof (gint16 *);
|
|
||||||
|
|
||||||
for (; i < len; i++) {
|
|
||||||
*i = g_ntohs (*i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
gst_rtpgsm_caps_nego (GstRtpGSMParse * rtpgsmparse)
|
gst_rtpgsm_caps_nego (GstRtpGSMParse * rtpgsmparse)
|
||||||
{
|
{
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
|
@ -166,72 +154,67 @@ gst_rtpgsm_caps_nego (GstRtpGSMParse * rtpgsmparse)
|
||||||
caps = gst_caps_new_simple ("audio/x-gsm",
|
caps = gst_caps_new_simple ("audio/x-gsm",
|
||||||
"rate", G_TYPE_INT, rtpgsmparse->frequency, NULL);
|
"rate", G_TYPE_INT, rtpgsmparse->frequency, NULL);
|
||||||
|
|
||||||
gst_pad_try_set_caps (rtpgsmparse->srcpad, caps);
|
gst_pad_set_caps (rtpgsmparse->srcpad, caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static GstFlowReturn
|
||||||
gst_rtpgsmparse_chain (GstPad * pad, GstData * _data)
|
gst_rtpgsmparse_chain (GstPad * pad, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstBuffer *buf = GST_BUFFER (_data);
|
|
||||||
GstRtpGSMParse *rtpgsmparse;
|
GstRtpGSMParse *rtpgsmparse;
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
Rtp_Packet packet;
|
GstFlowReturn ret;
|
||||||
rtp_payload_t pt;
|
guint8 pt;
|
||||||
|
|
||||||
g_return_if_fail (pad != NULL);
|
rtpgsmparse = GST_RTP_GSM_PARSE (gst_pad_get_parent (pad));
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
|
||||||
g_return_if_fail (buf != NULL);
|
|
||||||
|
|
||||||
rtpgsmparse = GST_RTP_GSM_PARSE (GST_OBJECT_PARENT (pad));
|
|
||||||
|
|
||||||
g_return_if_fail (rtpgsmparse != NULL);
|
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_PARSE (rtpgsmparse));
|
|
||||||
|
|
||||||
if (GST_IS_EVENT (buf)) {
|
|
||||||
GstEvent *event = GST_EVENT (buf);
|
|
||||||
|
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GST_PAD_CAPS (rtpgsmparse->srcpad) == NULL) {
|
if (GST_PAD_CAPS (rtpgsmparse->srcpad) == NULL) {
|
||||||
gst_rtpgsm_caps_nego (rtpgsmparse);
|
gst_rtpgsm_caps_nego (rtpgsmparse);
|
||||||
}
|
}
|
||||||
|
|
||||||
packet =
|
if (!gst_rtpbuffer_validate (buf))
|
||||||
rtp_packet_new_copy_data (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
goto bad_packet;
|
||||||
|
|
||||||
pt = rtp_packet_get_payload_type (packet);
|
if ((pt = gst_rtpbuffer_get_payload_type (buf)) != GST_RTP_PAYLOAD_GSM)
|
||||||
|
goto bad_payload;
|
||||||
|
|
||||||
|
{
|
||||||
|
gint payload_len;
|
||||||
|
guint8 *payload;
|
||||||
|
guint32 timestamp;
|
||||||
|
|
||||||
|
payload_len = gst_rtpbuffer_get_payload_len (buf);
|
||||||
|
payload = gst_rtpbuffer_get_payload (buf);
|
||||||
|
|
||||||
|
timestamp = gst_rtpbuffer_get_timestamp (buf);
|
||||||
|
|
||||||
|
outbuf = gst_buffer_new_and_alloc (payload_len);
|
||||||
|
|
||||||
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 8000;
|
||||||
|
|
||||||
|
memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
|
||||||
|
|
||||||
|
GST_DEBUG ("pushing buffer of size %d", GST_BUFFER_SIZE (outbuf));
|
||||||
|
|
||||||
if (pt != PAYLOAD_GSM) {
|
|
||||||
g_warning ("Unexpected paload type %u\n", pt);
|
|
||||||
rtp_packet_free (packet);
|
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
return;
|
|
||||||
|
ret = gst_pad_push (rtpgsmparse->srcpad, outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
outbuf = gst_buffer_new ();
|
return ret;
|
||||||
GST_BUFFER_SIZE (outbuf) = rtp_packet_get_payload_len (packet);
|
|
||||||
GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) =
|
|
||||||
g_ntohl (rtp_packet_get_timestamp (packet)) * GST_SECOND;
|
|
||||||
|
|
||||||
memcpy (GST_BUFFER_DATA (outbuf), rtp_packet_get_payload (packet),
|
bad_packet:
|
||||||
GST_BUFFER_SIZE (outbuf));
|
{
|
||||||
|
GST_DEBUG ("Packet did not validate");
|
||||||
GST_DEBUG ("gst_rtpgsmparse_chain: pushing buffer of size %d",
|
|
||||||
GST_BUFFER_SIZE (outbuf));
|
|
||||||
|
|
||||||
/* FIXME: According to RFC 1890, this is required, right? */
|
|
||||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
||||||
gst_rtpgsmparse_ntohs (outbuf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gst_pad_push (rtpgsmparse->srcpad, GST_DATA (outbuf));
|
|
||||||
|
|
||||||
rtp_packet_free (packet);
|
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
bad_payload:
|
||||||
|
{
|
||||||
|
GST_DEBUG ("Unexpected payload type %u", pt);
|
||||||
|
gst_buffer_unref (buf);
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -240,7 +223,6 @@ gst_rtpgsmparse_set_property (GObject * object, guint prop_id,
|
||||||
{
|
{
|
||||||
GstRtpGSMParse *rtpgsmparse;
|
GstRtpGSMParse *rtpgsmparse;
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_PARSE (object));
|
|
||||||
rtpgsmparse = GST_RTP_GSM_PARSE (object);
|
rtpgsmparse = GST_RTP_GSM_PARSE (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
|
@ -258,7 +240,6 @@ gst_rtpgsmparse_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
{
|
{
|
||||||
GstRtpGSMParse *rtpgsmparse;
|
GstRtpGSMParse *rtpgsmparse;
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_PARSE (object));
|
|
||||||
rtpgsmparse = GST_RTP_GSM_PARSE (object);
|
rtpgsmparse = GST_RTP_GSM_PARSE (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
|
@ -275,28 +256,26 @@ static GstStateChangeReturn
|
||||||
gst_rtpgsmparse_change_state (GstElement * element, GstStateChange transition)
|
gst_rtpgsmparse_change_state (GstElement * element, GstStateChange transition)
|
||||||
{
|
{
|
||||||
GstRtpGSMParse *rtpgsmparse;
|
GstRtpGSMParse *rtpgsmparse;
|
||||||
|
GstStateChangeReturn ret;
|
||||||
g_return_val_if_fail (GST_IS_RTP_GSM_PARSE (element),
|
|
||||||
GST_STATE_CHANGE_FAILURE);
|
|
||||||
|
|
||||||
rtpgsmparse = GST_RTP_GSM_PARSE (element);
|
rtpgsmparse = GST_RTP_GSM_PARSE (element);
|
||||||
|
|
||||||
GST_DEBUG ("state pending %d\n", GST_STATE_PENDING (element));
|
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we haven't failed already, give the parent class a chance to ;-) */
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
return GST_STATE_CHANGE_SUCCESS;
|
switch (transition) {
|
||||||
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|
|
@ -21,34 +21,12 @@
|
||||||
#define __GST_RTP_GSM_PARSE_H__
|
#define __GST_RTP_GSM_PARSE_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include "rtp-packet.h"
|
|
||||||
#include "gstrtp-common.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_BEGIN_DECLS
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
/* Definition of structure storing data for this element. */
|
|
||||||
typedef struct _GstRtpGSMParse GstRtpGSMParse;
|
typedef struct _GstRtpGSMParse GstRtpGSMParse;
|
||||||
struct _GstRtpGSMParse
|
|
||||||
{
|
|
||||||
GstElement element;
|
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
guint frequency;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Standard definition defining a class for this element. */
|
|
||||||
typedef struct _GstRtpGSMParseClass GstRtpGSMParseClass;
|
typedef struct _GstRtpGSMParseClass GstRtpGSMParseClass;
|
||||||
struct _GstRtpGSMParseClass
|
|
||||||
{
|
|
||||||
GstElementClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Standard macros for defining types for this element. */
|
|
||||||
#define GST_TYPE_RTP_GSM_PARSE \
|
#define GST_TYPE_RTP_GSM_PARSE \
|
||||||
(gst_rtpgsmparse_get_type())
|
(gst_rtpgsmparse_get_type())
|
||||||
#define GST_RTP_GSM_PARSE(obj) \
|
#define GST_RTP_GSM_PARSE(obj) \
|
||||||
|
@ -60,11 +38,23 @@ struct _GstRtpGSMParseClass
|
||||||
#define GST_IS_RTP_GSM_PARSE_CLASS(obj) \
|
#define GST_IS_RTP_GSM_PARSE_CLASS(obj) \
|
||||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_PARSE))
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_PARSE))
|
||||||
|
|
||||||
|
struct _GstRtpGSMParse
|
||||||
|
{
|
||||||
|
GstElement element;
|
||||||
|
|
||||||
|
GstPad *sinkpad;
|
||||||
|
GstPad *srcpad;
|
||||||
|
|
||||||
|
guint frequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstRtpGSMParseClass
|
||||||
|
{
|
||||||
|
GstElementClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
gboolean gst_rtpgsmparse_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtpgsmparse_plugin_init (GstPlugin * plugin);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_END_DECLS
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_RTP_GSM_PARSE_H__ */
|
#endif /* __GST_RTP_GSM_PARSE_H__ */
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <gst/rtp/gstrtpbuffer.h>
|
||||||
|
|
||||||
#include "gstrtpgsmenc.h"
|
#include "gstrtpgsmenc.h"
|
||||||
|
|
||||||
/* elementfactory information */
|
/* elementfactory information */
|
||||||
|
@ -33,19 +35,6 @@ static GstElementDetails gst_rtpgsmenc_details = {
|
||||||
"Zeeshan Ali <zak147@yahoo.com>"
|
"Zeeshan Ali <zak147@yahoo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RtpGSMEnc signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
ARG_0
|
|
||||||
};
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtpgsmenc_sink_template =
|
static GstStaticPadTemplate gst_rtpgsmenc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -57,24 +46,23 @@ static GstStaticPadTemplate gst_rtpgsmenc_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp")
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"audio\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 8000, " "encoding_name = (string) \"GSM\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void gst_rtpgsmenc_class_init (GstRtpGSMEncClass * klass);
|
static void gst_rtpgsmenc_class_init (GstRtpGSMEncClass * klass);
|
||||||
static void gst_rtpgsmenc_base_init (GstRtpGSMEncClass * klass);
|
static void gst_rtpgsmenc_base_init (GstRtpGSMEncClass * klass);
|
||||||
static void gst_rtpgsmenc_init (GstRtpGSMEnc * rtpgsmenc);
|
static void gst_rtpgsmenc_init (GstRtpGSMEnc * rtpgsmenc);
|
||||||
static void gst_rtpgsmenc_chain (GstPad * pad, GstData * _data);
|
|
||||||
static void gst_rtpgsmenc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_rtpgsmenc_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
static GstPadLinkReturn gst_rtpgsmenc_sinkconnect (GstPad * pad,
|
|
||||||
const GstCaps * caps);
|
|
||||||
static GstStateChangeReturn gst_rtpgsmenc_change_state (GstElement * element,
|
|
||||||
GstStateChange transition);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
static gboolean gst_rtpgsmenc_setcaps (GstBaseRTPPayload * payload,
|
||||||
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_rtpgsmenc_handle_buffer (GstBaseRTPPayload * payload,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
|
static GstBaseRTPPayloadClass *parent_class = NULL;
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gst_rtpgsmenc_get_type (void)
|
gst_rtpgsmenc_get_type (void)
|
||||||
|
@ -95,7 +83,7 @@ gst_rtpgsmenc_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
rtpgsmenc_type =
|
rtpgsmenc_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRtpGSMEnc",
|
g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpGSMEnc",
|
||||||
&rtpgsmenc_info, 0);
|
&rtpgsmenc_info, 0);
|
||||||
}
|
}
|
||||||
return rtpgsmenc_type;
|
return rtpgsmenc_type;
|
||||||
|
@ -118,209 +106,91 @@ gst_rtpgsmenc_class_init (GstRtpGSMEncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtpgsmenc_set_property;
|
gstbasertppayload_class->set_caps = gst_rtpgsmenc_setcaps;
|
||||||
gobject_class->get_property = gst_rtpgsmenc_get_property;
|
gstbasertppayload_class->handle_buffer = gst_rtpgsmenc_handle_buffer;
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtpgsmenc_change_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtpgsmenc_init (GstRtpGSMEnc * rtpgsmenc)
|
gst_rtpgsmenc_init (GstRtpGSMEnc * rtpgsmenc)
|
||||||
{
|
{
|
||||||
rtpgsmenc->sinkpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpgsmenc_sink_template), "sink");
|
|
||||||
rtpgsmenc->srcpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpgsmenc_src_template), "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpgsmenc), rtpgsmenc->sinkpad);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpgsmenc), rtpgsmenc->srcpad);
|
|
||||||
gst_pad_set_chain_function (rtpgsmenc->sinkpad, gst_rtpgsmenc_chain);
|
|
||||||
gst_pad_set_link_function (rtpgsmenc->sinkpad, gst_rtpgsmenc_sinkconnect);
|
|
||||||
|
|
||||||
rtpgsmenc->frequency = 8000;
|
rtpgsmenc->frequency = 8000;
|
||||||
|
|
||||||
rtpgsmenc->next_time = 0;
|
|
||||||
rtpgsmenc->time_interval = 0;
|
|
||||||
|
|
||||||
rtpgsmenc->seq = 0;
|
|
||||||
rtpgsmenc->ssrc = random ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstPadLinkReturn
|
static gboolean
|
||||||
gst_rtpgsmenc_sinkconnect (GstPad * pad, const GstCaps * caps)
|
gst_rtpgsmenc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstRtpGSMEnc *rtpgsmenc;
|
GstRtpGSMEnc *rtpgsmenc;
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
GstCaps *srccaps;
|
||||||
|
|
||||||
rtpgsmenc = GST_RTP_GSM_ENC (gst_pad_get_parent (pad));
|
rtpgsmenc = GST_RTP_GSM_ENC (payload);
|
||||||
|
|
||||||
structure = gst_caps_get_structure (caps, 0);
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
ret = gst_structure_get_int (structure, "rate", &rtpgsmenc->frequency);
|
ret = gst_structure_get_int (structure, "rate", &rtpgsmenc->frequency);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return GST_PAD_LINK_REFUSED;
|
return FALSE;
|
||||||
|
|
||||||
/* Pre-calculate what we can */
|
srccaps = gst_caps_new_simple ("application/x-rtp", NULL);
|
||||||
rtpgsmenc->time_interval = GST_SECOND / (2 * rtpgsmenc->frequency);
|
gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (rtpgsmenc), srccaps);
|
||||||
|
gst_caps_unref (srccaps);
|
||||||
|
|
||||||
return GST_PAD_LINK_OK;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
void
|
gst_rtpgsmenc_handle_buffer (GstBaseRTPPayload * basepayload,
|
||||||
gst_rtpgsmenc_htons (GstBuffer * buf)
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
gint16 *i, *len;
|
|
||||||
|
|
||||||
/* FIXME: is this code correct or even sane at all? */
|
|
||||||
i = (gint16 *) GST_BUFFER_DATA (buf);
|
|
||||||
len = i + GST_BUFFER_SIZE (buf) / sizeof (gint16 *);
|
|
||||||
|
|
||||||
for (; i < len; i++) {
|
|
||||||
*i = g_htons (*i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpgsmenc_chain (GstPad * pad, GstData * _data)
|
|
||||||
{
|
|
||||||
GstBuffer *buf = GST_BUFFER (_data);
|
|
||||||
GstRtpGSMEnc *rtpgsmenc;
|
GstRtpGSMEnc *rtpgsmenc;
|
||||||
|
guint size, payload_len;
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
Rtp_Packet packet;
|
guint8 *payload, *data;
|
||||||
|
GstClockTime timestamp;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
g_return_if_fail (pad != NULL);
|
rtpgsmenc = GST_RTP_GSM_ENC (basepayload);
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
|
||||||
g_return_if_fail (buf != NULL);
|
|
||||||
|
|
||||||
rtpgsmenc = GST_RTP_GSM_ENC (GST_OBJECT_PARENT (pad));
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
|
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
|
||||||
g_return_if_fail (rtpgsmenc != NULL);
|
/* FIXME, only one GSM frame per RTP packet for now */
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_ENC (rtpgsmenc));
|
payload_len = size;
|
||||||
|
|
||||||
if (GST_IS_EVENT (buf)) {
|
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
||||||
GstEvent *event = GST_EVENT (buf);
|
/* FIXME, assert for now */
|
||||||
|
g_assert (GST_BUFFER_SIZE (outbuf) < GST_BASE_RTP_PAYLOAD_MTU (rtpgsmenc));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
gst_rtpbuffer_set_timestamp (outbuf, timestamp * 8000 / GST_SECOND);
|
||||||
case GST_EVENT_DISCONTINUOUS:
|
|
||||||
GST_DEBUG ("discont");
|
|
||||||
rtpgsmenc->next_time = 0;
|
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We only need the header */
|
/* copy timestamp */
|
||||||
packet = rtp_packet_new_allocate (0, 0, 0);
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
||||||
|
|
||||||
rtp_packet_set_csrc_count (packet, 0);
|
/* get payload */
|
||||||
rtp_packet_set_extension (packet, 0);
|
payload = gst_rtpbuffer_get_payload (outbuf);
|
||||||
rtp_packet_set_padding (packet, 0);
|
|
||||||
rtp_packet_set_version (packet, RTP_VERSION);
|
|
||||||
rtp_packet_set_marker (packet, 0);
|
|
||||||
rtp_packet_set_ssrc (packet, g_htonl (rtpgsmenc->ssrc));
|
|
||||||
rtp_packet_set_seq (packet, g_htons (rtpgsmenc->seq));
|
|
||||||
rtp_packet_set_timestamp (packet,
|
|
||||||
g_htonl ((guint32) rtpgsmenc->next_time / GST_SECOND));
|
|
||||||
rtp_packet_set_payload_type (packet, (guint8) PAYLOAD_GSM);
|
|
||||||
|
|
||||||
/* FIXME: According to RFC 1890, this is required, right? */
|
data = GST_BUFFER_DATA (buffer);
|
||||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
||||||
gst_rtpgsmenc_htons (buf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
outbuf = gst_buffer_new ();
|
/* copy data in payload */
|
||||||
GST_BUFFER_SIZE (outbuf) =
|
memcpy (&payload[0], data, size);
|
||||||
rtp_packet_get_packet_len (packet) + GST_BUFFER_SIZE (buf);
|
|
||||||
GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = rtpgsmenc->next_time;
|
|
||||||
|
|
||||||
memcpy (GST_BUFFER_DATA (outbuf), packet->data,
|
gst_buffer_unref (buffer);
|
||||||
rtp_packet_get_packet_len (packet));
|
|
||||||
memcpy (GST_BUFFER_DATA (outbuf) + rtp_packet_get_packet_len (packet),
|
|
||||||
GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
|
||||||
|
|
||||||
GST_DEBUG ("gst_rtpgsmenc_chain: pushing buffer of size %d",
|
GST_DEBUG ("gst_rtpgsmenc_chain: pushing buffer of size %d",
|
||||||
GST_BUFFER_SIZE (outbuf));
|
GST_BUFFER_SIZE (outbuf));
|
||||||
gst_pad_push (rtpgsmenc->srcpad, GST_DATA (outbuf));
|
|
||||||
|
|
||||||
++rtpgsmenc->seq;
|
ret = gst_basertppayload_push (basepayload, outbuf);
|
||||||
rtpgsmenc->next_time += rtpgsmenc->time_interval * GST_BUFFER_SIZE (buf);
|
|
||||||
|
|
||||||
rtp_packet_free (packet);
|
return ret;
|
||||||
gst_buffer_unref (buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpgsmenc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpGSMEnc *rtpgsmenc;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_ENC (object));
|
|
||||||
rtpgsmenc = GST_RTP_GSM_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpgsmenc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpGSMEnc *rtpgsmenc;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_ENC (object));
|
|
||||||
rtpgsmenc = GST_RTP_GSM_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_rtpgsmenc_change_state (GstElement * element, GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstRtpGSMEnc *rtpgsmenc;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_RTP_GSM_ENC (element), GST_STATE_CHANGE_FAILURE);
|
|
||||||
|
|
||||||
rtpgsmenc = GST_RTP_GSM_ENC (element);
|
|
||||||
|
|
||||||
GST_DEBUG ("state pending %d\n", GST_STATE_PENDING (element));
|
|
||||||
|
|
||||||
/* if going down into NULL state, close the file if it's open */
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if we haven't failed already, give the parent class a chance to ;-) */
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
return GST_STATE_CHANGE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|
|
@ -22,42 +22,13 @@
|
||||||
#define __GST_RTP_GSM_ENC_H__
|
#define __GST_RTP_GSM_ENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include "rtp-packet.h"
|
#include <gst/rtp/gstbasertppayload.h>
|
||||||
#include "gstrtp-common.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_BEGIN_DECLS
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
/* Definition of structure storing data for this element. */
|
|
||||||
typedef struct _GstRtpGSMEnc GstRtpGSMEnc;
|
typedef struct _GstRtpGSMEnc GstRtpGSMEnc;
|
||||||
struct _GstRtpGSMEnc
|
|
||||||
{
|
|
||||||
GstElement element;
|
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
guint frequency;
|
|
||||||
|
|
||||||
/* the timestamp of the next frame */
|
|
||||||
guint64 next_time;
|
|
||||||
/* the interval between frames */
|
|
||||||
guint64 time_interval;
|
|
||||||
|
|
||||||
guint32 ssrc;
|
|
||||||
guint16 seq;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Standard definition defining a class for this element. */
|
|
||||||
typedef struct _GstRtpGSMEncClass GstRtpGSMEncClass;
|
typedef struct _GstRtpGSMEncClass GstRtpGSMEncClass;
|
||||||
struct _GstRtpGSMEncClass
|
|
||||||
{
|
|
||||||
GstElementClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Standard macros for defining types for this element. */
|
|
||||||
#define GST_TYPE_RTP_GSM_ENC \
|
#define GST_TYPE_RTP_GSM_ENC \
|
||||||
(gst_rtpgsmenc_get_type())
|
(gst_rtpgsmenc_get_type())
|
||||||
#define GST_RTP_GSM_ENC(obj) \
|
#define GST_RTP_GSM_ENC(obj) \
|
||||||
|
@ -69,11 +40,20 @@ struct _GstRtpGSMEncClass
|
||||||
#define GST_IS_RTP_GSM_ENC_CLASS(obj) \
|
#define GST_IS_RTP_GSM_ENC_CLASS(obj) \
|
||||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_ENC))
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_ENC))
|
||||||
|
|
||||||
|
struct _GstRtpGSMEnc
|
||||||
|
{
|
||||||
|
GstBaseRTPPayload payload;
|
||||||
|
|
||||||
|
gint frequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstRtpGSMEncClass
|
||||||
|
{
|
||||||
|
GstBaseRTPPayloadClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
gboolean gst_rtpgsmenc_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtpgsmenc_plugin_init (GstPlugin * plugin);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_END_DECLS
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_RTP_GSM_ENC_H__ */
|
#endif /* __GST_RTP_GSM_ENC_H__ */
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <gst/rtp/gstrtpbuffer.h>
|
||||||
#include "gstrtpgsmparse.h"
|
#include "gstrtpgsmparse.h"
|
||||||
#include "gstrtp-common.h"
|
|
||||||
|
|
||||||
/* elementfactory information */
|
/* elementfactory information */
|
||||||
static GstElementDetails gst_rtp_gsmparse_details = {
|
static GstElementDetails gst_rtp_gsmparse_details = {
|
||||||
|
@ -60,13 +60,15 @@ static void gst_rtpgsmparse_class_init (GstRtpGSMParseClass * klass);
|
||||||
static void gst_rtpgsmparse_base_init (GstRtpGSMParseClass * klass);
|
static void gst_rtpgsmparse_base_init (GstRtpGSMParseClass * klass);
|
||||||
static void gst_rtpgsmparse_init (GstRtpGSMParse * rtpgsmparse);
|
static void gst_rtpgsmparse_init (GstRtpGSMParse * rtpgsmparse);
|
||||||
|
|
||||||
static void gst_rtpgsmparse_chain (GstPad * pad, GstData * _data);
|
static GstFlowReturn gst_rtpgsmparse_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
|
|
||||||
static void gst_rtpgsmparse_set_property (GObject * object, guint prop_id,
|
static void gst_rtpgsmparse_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
static void gst_rtpgsmparse_get_property (GObject * object, guint prop_id,
|
static void gst_rtpgsmparse_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
static GstStateChangeReturn gst_rtpgsmparse_change_state (GstElement * element);
|
|
||||||
|
static GstStateChangeReturn gst_rtpgsmparse_change_state (GstElement * element,
|
||||||
|
GstStateChange transition);
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
static GstElementClass *parent_class = NULL;
|
||||||
|
|
||||||
|
@ -118,13 +120,13 @@ gst_rtpgsmparse_class_init (GstRtpGSMParseClass * klass)
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
|
gobject_class->set_property = gst_rtpgsmparse_set_property;
|
||||||
|
gobject_class->get_property = gst_rtpgsmparse_get_property;
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FREQUENCY,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FREQUENCY,
|
||||||
g_param_spec_int ("frequency", "frequency", "frequency",
|
g_param_spec_int ("frequency", "frequency", "frequency",
|
||||||
G_MININT, G_MAXINT, 8000, G_PARAM_READWRITE));
|
G_MININT, G_MAXINT, 8000, G_PARAM_READWRITE));
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtpgsmparse_set_property;
|
|
||||||
gobject_class->get_property = gst_rtpgsmparse_get_property;
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtpgsmparse_change_state;
|
gstelement_class->change_state = gst_rtpgsmparse_change_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,21 +146,7 @@ gst_rtpgsmparse_init (GstRtpGSMParse * rtpgsmparse)
|
||||||
rtpgsmparse->frequency = 8000;
|
rtpgsmparse->frequency = 8000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
gst_rtpgsmparse_ntohs (GstBuffer * buf)
|
|
||||||
{
|
|
||||||
gint16 *i, *len;
|
|
||||||
|
|
||||||
/* FIXME: is this code correct or even sane at all? */
|
|
||||||
i = (gint16 *) GST_BUFFER_DATA (buf);
|
|
||||||
len = i + GST_BUFFER_SIZE (buf) / sizeof (gint16 *);
|
|
||||||
|
|
||||||
for (; i < len; i++) {
|
|
||||||
*i = g_ntohs (*i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
gst_rtpgsm_caps_nego (GstRtpGSMParse * rtpgsmparse)
|
gst_rtpgsm_caps_nego (GstRtpGSMParse * rtpgsmparse)
|
||||||
{
|
{
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
|
@ -166,72 +154,67 @@ gst_rtpgsm_caps_nego (GstRtpGSMParse * rtpgsmparse)
|
||||||
caps = gst_caps_new_simple ("audio/x-gsm",
|
caps = gst_caps_new_simple ("audio/x-gsm",
|
||||||
"rate", G_TYPE_INT, rtpgsmparse->frequency, NULL);
|
"rate", G_TYPE_INT, rtpgsmparse->frequency, NULL);
|
||||||
|
|
||||||
gst_pad_try_set_caps (rtpgsmparse->srcpad, caps);
|
gst_pad_set_caps (rtpgsmparse->srcpad, caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static GstFlowReturn
|
||||||
gst_rtpgsmparse_chain (GstPad * pad, GstData * _data)
|
gst_rtpgsmparse_chain (GstPad * pad, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstBuffer *buf = GST_BUFFER (_data);
|
|
||||||
GstRtpGSMParse *rtpgsmparse;
|
GstRtpGSMParse *rtpgsmparse;
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
Rtp_Packet packet;
|
GstFlowReturn ret;
|
||||||
rtp_payload_t pt;
|
guint8 pt;
|
||||||
|
|
||||||
g_return_if_fail (pad != NULL);
|
rtpgsmparse = GST_RTP_GSM_PARSE (gst_pad_get_parent (pad));
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
|
||||||
g_return_if_fail (buf != NULL);
|
|
||||||
|
|
||||||
rtpgsmparse = GST_RTP_GSM_PARSE (GST_OBJECT_PARENT (pad));
|
|
||||||
|
|
||||||
g_return_if_fail (rtpgsmparse != NULL);
|
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_PARSE (rtpgsmparse));
|
|
||||||
|
|
||||||
if (GST_IS_EVENT (buf)) {
|
|
||||||
GstEvent *event = GST_EVENT (buf);
|
|
||||||
|
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GST_PAD_CAPS (rtpgsmparse->srcpad) == NULL) {
|
if (GST_PAD_CAPS (rtpgsmparse->srcpad) == NULL) {
|
||||||
gst_rtpgsm_caps_nego (rtpgsmparse);
|
gst_rtpgsm_caps_nego (rtpgsmparse);
|
||||||
}
|
}
|
||||||
|
|
||||||
packet =
|
if (!gst_rtpbuffer_validate (buf))
|
||||||
rtp_packet_new_copy_data (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
goto bad_packet;
|
||||||
|
|
||||||
pt = rtp_packet_get_payload_type (packet);
|
if ((pt = gst_rtpbuffer_get_payload_type (buf)) != GST_RTP_PAYLOAD_GSM)
|
||||||
|
goto bad_payload;
|
||||||
|
|
||||||
|
{
|
||||||
|
gint payload_len;
|
||||||
|
guint8 *payload;
|
||||||
|
guint32 timestamp;
|
||||||
|
|
||||||
|
payload_len = gst_rtpbuffer_get_payload_len (buf);
|
||||||
|
payload = gst_rtpbuffer_get_payload (buf);
|
||||||
|
|
||||||
|
timestamp = gst_rtpbuffer_get_timestamp (buf);
|
||||||
|
|
||||||
|
outbuf = gst_buffer_new_and_alloc (payload_len);
|
||||||
|
|
||||||
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 8000;
|
||||||
|
|
||||||
|
memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
|
||||||
|
|
||||||
|
GST_DEBUG ("pushing buffer of size %d", GST_BUFFER_SIZE (outbuf));
|
||||||
|
|
||||||
if (pt != PAYLOAD_GSM) {
|
|
||||||
g_warning ("Unexpected paload type %u\n", pt);
|
|
||||||
rtp_packet_free (packet);
|
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
return;
|
|
||||||
|
ret = gst_pad_push (rtpgsmparse->srcpad, outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
outbuf = gst_buffer_new ();
|
return ret;
|
||||||
GST_BUFFER_SIZE (outbuf) = rtp_packet_get_payload_len (packet);
|
|
||||||
GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) =
|
|
||||||
g_ntohl (rtp_packet_get_timestamp (packet)) * GST_SECOND;
|
|
||||||
|
|
||||||
memcpy (GST_BUFFER_DATA (outbuf), rtp_packet_get_payload (packet),
|
bad_packet:
|
||||||
GST_BUFFER_SIZE (outbuf));
|
{
|
||||||
|
GST_DEBUG ("Packet did not validate");
|
||||||
GST_DEBUG ("gst_rtpgsmparse_chain: pushing buffer of size %d",
|
|
||||||
GST_BUFFER_SIZE (outbuf));
|
|
||||||
|
|
||||||
/* FIXME: According to RFC 1890, this is required, right? */
|
|
||||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
||||||
gst_rtpgsmparse_ntohs (outbuf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gst_pad_push (rtpgsmparse->srcpad, GST_DATA (outbuf));
|
|
||||||
|
|
||||||
rtp_packet_free (packet);
|
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
bad_payload:
|
||||||
|
{
|
||||||
|
GST_DEBUG ("Unexpected payload type %u", pt);
|
||||||
|
gst_buffer_unref (buf);
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -240,7 +223,6 @@ gst_rtpgsmparse_set_property (GObject * object, guint prop_id,
|
||||||
{
|
{
|
||||||
GstRtpGSMParse *rtpgsmparse;
|
GstRtpGSMParse *rtpgsmparse;
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_PARSE (object));
|
|
||||||
rtpgsmparse = GST_RTP_GSM_PARSE (object);
|
rtpgsmparse = GST_RTP_GSM_PARSE (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
|
@ -258,7 +240,6 @@ gst_rtpgsmparse_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
{
|
{
|
||||||
GstRtpGSMParse *rtpgsmparse;
|
GstRtpGSMParse *rtpgsmparse;
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_PARSE (object));
|
|
||||||
rtpgsmparse = GST_RTP_GSM_PARSE (object);
|
rtpgsmparse = GST_RTP_GSM_PARSE (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
|
@ -275,28 +256,26 @@ static GstStateChangeReturn
|
||||||
gst_rtpgsmparse_change_state (GstElement * element, GstStateChange transition)
|
gst_rtpgsmparse_change_state (GstElement * element, GstStateChange transition)
|
||||||
{
|
{
|
||||||
GstRtpGSMParse *rtpgsmparse;
|
GstRtpGSMParse *rtpgsmparse;
|
||||||
|
GstStateChangeReturn ret;
|
||||||
g_return_val_if_fail (GST_IS_RTP_GSM_PARSE (element),
|
|
||||||
GST_STATE_CHANGE_FAILURE);
|
|
||||||
|
|
||||||
rtpgsmparse = GST_RTP_GSM_PARSE (element);
|
rtpgsmparse = GST_RTP_GSM_PARSE (element);
|
||||||
|
|
||||||
GST_DEBUG ("state pending %d\n", GST_STATE_PENDING (element));
|
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we haven't failed already, give the parent class a chance to ;-) */
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
return GST_STATE_CHANGE_SUCCESS;
|
switch (transition) {
|
||||||
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|
|
@ -21,34 +21,12 @@
|
||||||
#define __GST_RTP_GSM_PARSE_H__
|
#define __GST_RTP_GSM_PARSE_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include "rtp-packet.h"
|
|
||||||
#include "gstrtp-common.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_BEGIN_DECLS
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
/* Definition of structure storing data for this element. */
|
|
||||||
typedef struct _GstRtpGSMParse GstRtpGSMParse;
|
typedef struct _GstRtpGSMParse GstRtpGSMParse;
|
||||||
struct _GstRtpGSMParse
|
|
||||||
{
|
|
||||||
GstElement element;
|
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
guint frequency;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Standard definition defining a class for this element. */
|
|
||||||
typedef struct _GstRtpGSMParseClass GstRtpGSMParseClass;
|
typedef struct _GstRtpGSMParseClass GstRtpGSMParseClass;
|
||||||
struct _GstRtpGSMParseClass
|
|
||||||
{
|
|
||||||
GstElementClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Standard macros for defining types for this element. */
|
|
||||||
#define GST_TYPE_RTP_GSM_PARSE \
|
#define GST_TYPE_RTP_GSM_PARSE \
|
||||||
(gst_rtpgsmparse_get_type())
|
(gst_rtpgsmparse_get_type())
|
||||||
#define GST_RTP_GSM_PARSE(obj) \
|
#define GST_RTP_GSM_PARSE(obj) \
|
||||||
|
@ -60,11 +38,23 @@ struct _GstRtpGSMParseClass
|
||||||
#define GST_IS_RTP_GSM_PARSE_CLASS(obj) \
|
#define GST_IS_RTP_GSM_PARSE_CLASS(obj) \
|
||||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_PARSE))
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_PARSE))
|
||||||
|
|
||||||
|
struct _GstRtpGSMParse
|
||||||
|
{
|
||||||
|
GstElement element;
|
||||||
|
|
||||||
|
GstPad *sinkpad;
|
||||||
|
GstPad *srcpad;
|
||||||
|
|
||||||
|
guint frequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstRtpGSMParseClass
|
||||||
|
{
|
||||||
|
GstElementClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
gboolean gst_rtpgsmparse_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtpgsmparse_plugin_init (GstPlugin * plugin);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_END_DECLS
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_RTP_GSM_PARSE_H__ */
|
#endif /* __GST_RTP_GSM_PARSE_H__ */
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <gst/rtp/gstrtpbuffer.h>
|
||||||
|
|
||||||
#include "gstrtpgsmenc.h"
|
#include "gstrtpgsmenc.h"
|
||||||
|
|
||||||
/* elementfactory information */
|
/* elementfactory information */
|
||||||
|
@ -33,19 +35,6 @@ static GstElementDetails gst_rtpgsmenc_details = {
|
||||||
"Zeeshan Ali <zak147@yahoo.com>"
|
"Zeeshan Ali <zak147@yahoo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RtpGSMEnc signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
ARG_0
|
|
||||||
};
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtpgsmenc_sink_template =
|
static GstStaticPadTemplate gst_rtpgsmenc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -57,24 +46,23 @@ static GstStaticPadTemplate gst_rtpgsmenc_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp")
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"audio\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 8000, " "encoding_name = (string) \"GSM\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void gst_rtpgsmenc_class_init (GstRtpGSMEncClass * klass);
|
static void gst_rtpgsmenc_class_init (GstRtpGSMEncClass * klass);
|
||||||
static void gst_rtpgsmenc_base_init (GstRtpGSMEncClass * klass);
|
static void gst_rtpgsmenc_base_init (GstRtpGSMEncClass * klass);
|
||||||
static void gst_rtpgsmenc_init (GstRtpGSMEnc * rtpgsmenc);
|
static void gst_rtpgsmenc_init (GstRtpGSMEnc * rtpgsmenc);
|
||||||
static void gst_rtpgsmenc_chain (GstPad * pad, GstData * _data);
|
|
||||||
static void gst_rtpgsmenc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_rtpgsmenc_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
static GstPadLinkReturn gst_rtpgsmenc_sinkconnect (GstPad * pad,
|
|
||||||
const GstCaps * caps);
|
|
||||||
static GstStateChangeReturn gst_rtpgsmenc_change_state (GstElement * element,
|
|
||||||
GstStateChange transition);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
static gboolean gst_rtpgsmenc_setcaps (GstBaseRTPPayload * payload,
|
||||||
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_rtpgsmenc_handle_buffer (GstBaseRTPPayload * payload,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
|
static GstBaseRTPPayloadClass *parent_class = NULL;
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gst_rtpgsmenc_get_type (void)
|
gst_rtpgsmenc_get_type (void)
|
||||||
|
@ -95,7 +83,7 @@ gst_rtpgsmenc_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
rtpgsmenc_type =
|
rtpgsmenc_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRtpGSMEnc",
|
g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpGSMEnc",
|
||||||
&rtpgsmenc_info, 0);
|
&rtpgsmenc_info, 0);
|
||||||
}
|
}
|
||||||
return rtpgsmenc_type;
|
return rtpgsmenc_type;
|
||||||
|
@ -118,209 +106,91 @@ gst_rtpgsmenc_class_init (GstRtpGSMEncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtpgsmenc_set_property;
|
gstbasertppayload_class->set_caps = gst_rtpgsmenc_setcaps;
|
||||||
gobject_class->get_property = gst_rtpgsmenc_get_property;
|
gstbasertppayload_class->handle_buffer = gst_rtpgsmenc_handle_buffer;
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtpgsmenc_change_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtpgsmenc_init (GstRtpGSMEnc * rtpgsmenc)
|
gst_rtpgsmenc_init (GstRtpGSMEnc * rtpgsmenc)
|
||||||
{
|
{
|
||||||
rtpgsmenc->sinkpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpgsmenc_sink_template), "sink");
|
|
||||||
rtpgsmenc->srcpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpgsmenc_src_template), "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpgsmenc), rtpgsmenc->sinkpad);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpgsmenc), rtpgsmenc->srcpad);
|
|
||||||
gst_pad_set_chain_function (rtpgsmenc->sinkpad, gst_rtpgsmenc_chain);
|
|
||||||
gst_pad_set_link_function (rtpgsmenc->sinkpad, gst_rtpgsmenc_sinkconnect);
|
|
||||||
|
|
||||||
rtpgsmenc->frequency = 8000;
|
rtpgsmenc->frequency = 8000;
|
||||||
|
|
||||||
rtpgsmenc->next_time = 0;
|
|
||||||
rtpgsmenc->time_interval = 0;
|
|
||||||
|
|
||||||
rtpgsmenc->seq = 0;
|
|
||||||
rtpgsmenc->ssrc = random ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstPadLinkReturn
|
static gboolean
|
||||||
gst_rtpgsmenc_sinkconnect (GstPad * pad, const GstCaps * caps)
|
gst_rtpgsmenc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstRtpGSMEnc *rtpgsmenc;
|
GstRtpGSMEnc *rtpgsmenc;
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
GstCaps *srccaps;
|
||||||
|
|
||||||
rtpgsmenc = GST_RTP_GSM_ENC (gst_pad_get_parent (pad));
|
rtpgsmenc = GST_RTP_GSM_ENC (payload);
|
||||||
|
|
||||||
structure = gst_caps_get_structure (caps, 0);
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
ret = gst_structure_get_int (structure, "rate", &rtpgsmenc->frequency);
|
ret = gst_structure_get_int (structure, "rate", &rtpgsmenc->frequency);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return GST_PAD_LINK_REFUSED;
|
return FALSE;
|
||||||
|
|
||||||
/* Pre-calculate what we can */
|
srccaps = gst_caps_new_simple ("application/x-rtp", NULL);
|
||||||
rtpgsmenc->time_interval = GST_SECOND / (2 * rtpgsmenc->frequency);
|
gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (rtpgsmenc), srccaps);
|
||||||
|
gst_caps_unref (srccaps);
|
||||||
|
|
||||||
return GST_PAD_LINK_OK;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
void
|
gst_rtpgsmenc_handle_buffer (GstBaseRTPPayload * basepayload,
|
||||||
gst_rtpgsmenc_htons (GstBuffer * buf)
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
gint16 *i, *len;
|
|
||||||
|
|
||||||
/* FIXME: is this code correct or even sane at all? */
|
|
||||||
i = (gint16 *) GST_BUFFER_DATA (buf);
|
|
||||||
len = i + GST_BUFFER_SIZE (buf) / sizeof (gint16 *);
|
|
||||||
|
|
||||||
for (; i < len; i++) {
|
|
||||||
*i = g_htons (*i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpgsmenc_chain (GstPad * pad, GstData * _data)
|
|
||||||
{
|
|
||||||
GstBuffer *buf = GST_BUFFER (_data);
|
|
||||||
GstRtpGSMEnc *rtpgsmenc;
|
GstRtpGSMEnc *rtpgsmenc;
|
||||||
|
guint size, payload_len;
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
Rtp_Packet packet;
|
guint8 *payload, *data;
|
||||||
|
GstClockTime timestamp;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
g_return_if_fail (pad != NULL);
|
rtpgsmenc = GST_RTP_GSM_ENC (basepayload);
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
|
||||||
g_return_if_fail (buf != NULL);
|
|
||||||
|
|
||||||
rtpgsmenc = GST_RTP_GSM_ENC (GST_OBJECT_PARENT (pad));
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
|
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
|
||||||
g_return_if_fail (rtpgsmenc != NULL);
|
/* FIXME, only one GSM frame per RTP packet for now */
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_ENC (rtpgsmenc));
|
payload_len = size;
|
||||||
|
|
||||||
if (GST_IS_EVENT (buf)) {
|
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
||||||
GstEvent *event = GST_EVENT (buf);
|
/* FIXME, assert for now */
|
||||||
|
g_assert (GST_BUFFER_SIZE (outbuf) < GST_BASE_RTP_PAYLOAD_MTU (rtpgsmenc));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
gst_rtpbuffer_set_timestamp (outbuf, timestamp * 8000 / GST_SECOND);
|
||||||
case GST_EVENT_DISCONTINUOUS:
|
|
||||||
GST_DEBUG ("discont");
|
|
||||||
rtpgsmenc->next_time = 0;
|
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We only need the header */
|
/* copy timestamp */
|
||||||
packet = rtp_packet_new_allocate (0, 0, 0);
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
||||||
|
|
||||||
rtp_packet_set_csrc_count (packet, 0);
|
/* get payload */
|
||||||
rtp_packet_set_extension (packet, 0);
|
payload = gst_rtpbuffer_get_payload (outbuf);
|
||||||
rtp_packet_set_padding (packet, 0);
|
|
||||||
rtp_packet_set_version (packet, RTP_VERSION);
|
|
||||||
rtp_packet_set_marker (packet, 0);
|
|
||||||
rtp_packet_set_ssrc (packet, g_htonl (rtpgsmenc->ssrc));
|
|
||||||
rtp_packet_set_seq (packet, g_htons (rtpgsmenc->seq));
|
|
||||||
rtp_packet_set_timestamp (packet,
|
|
||||||
g_htonl ((guint32) rtpgsmenc->next_time / GST_SECOND));
|
|
||||||
rtp_packet_set_payload_type (packet, (guint8) PAYLOAD_GSM);
|
|
||||||
|
|
||||||
/* FIXME: According to RFC 1890, this is required, right? */
|
data = GST_BUFFER_DATA (buffer);
|
||||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
||||||
gst_rtpgsmenc_htons (buf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
outbuf = gst_buffer_new ();
|
/* copy data in payload */
|
||||||
GST_BUFFER_SIZE (outbuf) =
|
memcpy (&payload[0], data, size);
|
||||||
rtp_packet_get_packet_len (packet) + GST_BUFFER_SIZE (buf);
|
|
||||||
GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = rtpgsmenc->next_time;
|
|
||||||
|
|
||||||
memcpy (GST_BUFFER_DATA (outbuf), packet->data,
|
gst_buffer_unref (buffer);
|
||||||
rtp_packet_get_packet_len (packet));
|
|
||||||
memcpy (GST_BUFFER_DATA (outbuf) + rtp_packet_get_packet_len (packet),
|
|
||||||
GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
|
||||||
|
|
||||||
GST_DEBUG ("gst_rtpgsmenc_chain: pushing buffer of size %d",
|
GST_DEBUG ("gst_rtpgsmenc_chain: pushing buffer of size %d",
|
||||||
GST_BUFFER_SIZE (outbuf));
|
GST_BUFFER_SIZE (outbuf));
|
||||||
gst_pad_push (rtpgsmenc->srcpad, GST_DATA (outbuf));
|
|
||||||
|
|
||||||
++rtpgsmenc->seq;
|
ret = gst_basertppayload_push (basepayload, outbuf);
|
||||||
rtpgsmenc->next_time += rtpgsmenc->time_interval * GST_BUFFER_SIZE (buf);
|
|
||||||
|
|
||||||
rtp_packet_free (packet);
|
return ret;
|
||||||
gst_buffer_unref (buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpgsmenc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpGSMEnc *rtpgsmenc;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_ENC (object));
|
|
||||||
rtpgsmenc = GST_RTP_GSM_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpgsmenc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpGSMEnc *rtpgsmenc;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTP_GSM_ENC (object));
|
|
||||||
rtpgsmenc = GST_RTP_GSM_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_rtpgsmenc_change_state (GstElement * element, GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstRtpGSMEnc *rtpgsmenc;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_RTP_GSM_ENC (element), GST_STATE_CHANGE_FAILURE);
|
|
||||||
|
|
||||||
rtpgsmenc = GST_RTP_GSM_ENC (element);
|
|
||||||
|
|
||||||
GST_DEBUG ("state pending %d\n", GST_STATE_PENDING (element));
|
|
||||||
|
|
||||||
/* if going down into NULL state, close the file if it's open */
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if we haven't failed already, give the parent class a chance to ;-) */
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
return GST_STATE_CHANGE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|
|
@ -22,42 +22,13 @@
|
||||||
#define __GST_RTP_GSM_ENC_H__
|
#define __GST_RTP_GSM_ENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include "rtp-packet.h"
|
#include <gst/rtp/gstbasertppayload.h>
|
||||||
#include "gstrtp-common.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_BEGIN_DECLS
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
/* Definition of structure storing data for this element. */
|
|
||||||
typedef struct _GstRtpGSMEnc GstRtpGSMEnc;
|
typedef struct _GstRtpGSMEnc GstRtpGSMEnc;
|
||||||
struct _GstRtpGSMEnc
|
|
||||||
{
|
|
||||||
GstElement element;
|
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
guint frequency;
|
|
||||||
|
|
||||||
/* the timestamp of the next frame */
|
|
||||||
guint64 next_time;
|
|
||||||
/* the interval between frames */
|
|
||||||
guint64 time_interval;
|
|
||||||
|
|
||||||
guint32 ssrc;
|
|
||||||
guint16 seq;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Standard definition defining a class for this element. */
|
|
||||||
typedef struct _GstRtpGSMEncClass GstRtpGSMEncClass;
|
typedef struct _GstRtpGSMEncClass GstRtpGSMEncClass;
|
||||||
struct _GstRtpGSMEncClass
|
|
||||||
{
|
|
||||||
GstElementClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Standard macros for defining types for this element. */
|
|
||||||
#define GST_TYPE_RTP_GSM_ENC \
|
#define GST_TYPE_RTP_GSM_ENC \
|
||||||
(gst_rtpgsmenc_get_type())
|
(gst_rtpgsmenc_get_type())
|
||||||
#define GST_RTP_GSM_ENC(obj) \
|
#define GST_RTP_GSM_ENC(obj) \
|
||||||
|
@ -69,11 +40,20 @@ struct _GstRtpGSMEncClass
|
||||||
#define GST_IS_RTP_GSM_ENC_CLASS(obj) \
|
#define GST_IS_RTP_GSM_ENC_CLASS(obj) \
|
||||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_ENC))
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_ENC))
|
||||||
|
|
||||||
|
struct _GstRtpGSMEnc
|
||||||
|
{
|
||||||
|
GstBaseRTPPayload payload;
|
||||||
|
|
||||||
|
gint frequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstRtpGSMEncClass
|
||||||
|
{
|
||||||
|
GstBaseRTPPayloadClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
gboolean gst_rtpgsmenc_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtpgsmenc_plugin_init (GstPlugin * plugin);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_END_DECLS
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_RTP_GSM_ENC_H__ */
|
#endif /* __GST_RTP_GSM_ENC_H__ */
|
||||||
|
|
|
@ -53,13 +53,17 @@ static GstStaticPadTemplate gst_rtph263pdec_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp")
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"video\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 90000, " "encoding_name = (string) \"H263-1998\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void gst_rtph263pdec_class_init (GstRtpH263PDecClass * klass);
|
static void gst_rtph263pdec_class_init (GstRtpH263PDecClass * klass);
|
||||||
static void gst_rtph263pdec_base_init (GstRtpH263PDecClass * klass);
|
static void gst_rtph263pdec_base_init (GstRtpH263PDecClass * klass);
|
||||||
static void gst_rtph263pdec_init (GstRtpH263PDec * rtph263pdec);
|
static void gst_rtph263pdec_init (GstRtpH263PDec * rtph263pdec);
|
||||||
|
static void gst_rtph263pdec_finalize (GObject * object);
|
||||||
|
|
||||||
static GstFlowReturn gst_rtph263pdec_chain (GstPad * pad, GstBuffer * buffer);
|
static GstFlowReturn gst_rtph263pdec_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
|
|
||||||
|
@ -122,6 +126,8 @@ gst_rtph263pdec_class_init (GstRtpH263PDecClass * klass)
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
|
gobject_class->finalize = gst_rtph263pdec_finalize;
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtph263pdec_set_property;
|
gobject_class->set_property = gst_rtph263pdec_set_property;
|
||||||
gobject_class->get_property = gst_rtph263pdec_get_property;
|
gobject_class->get_property = gst_rtph263pdec_get_property;
|
||||||
|
|
||||||
|
@ -145,6 +151,19 @@ gst_rtph263pdec_init (GstRtpH263PDec * rtph263pdec)
|
||||||
rtph263pdec->adapter = gst_adapter_new ();
|
rtph263pdec->adapter = gst_adapter_new ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtph263pdec_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
GstRtpH263PDec *rtph263pdec;
|
||||||
|
|
||||||
|
rtph263pdec = GST_RTP_H263P_DEC (object);
|
||||||
|
|
||||||
|
g_object_unref (rtph263pdec->adapter);
|
||||||
|
rtph263pdec->adapter = NULL;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtph263pdec_chain (GstPad * pad, GstBuffer * buf)
|
gst_rtph263pdec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
@ -292,6 +311,9 @@ gst_rtph263pdec_change_state (GstElement * element, GstStateChange transition)
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
|
gst_adapter_clear (rtph263pdec->adapter);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,13 +53,17 @@ static GstStaticPadTemplate gst_rtph263pdec_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp")
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"video\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 90000, " "encoding_name = (string) \"H263-1998\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void gst_rtph263pdec_class_init (GstRtpH263PDecClass * klass);
|
static void gst_rtph263pdec_class_init (GstRtpH263PDecClass * klass);
|
||||||
static void gst_rtph263pdec_base_init (GstRtpH263PDecClass * klass);
|
static void gst_rtph263pdec_base_init (GstRtpH263PDecClass * klass);
|
||||||
static void gst_rtph263pdec_init (GstRtpH263PDec * rtph263pdec);
|
static void gst_rtph263pdec_init (GstRtpH263PDec * rtph263pdec);
|
||||||
|
static void gst_rtph263pdec_finalize (GObject * object);
|
||||||
|
|
||||||
static GstFlowReturn gst_rtph263pdec_chain (GstPad * pad, GstBuffer * buffer);
|
static GstFlowReturn gst_rtph263pdec_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
|
|
||||||
|
@ -122,6 +126,8 @@ gst_rtph263pdec_class_init (GstRtpH263PDecClass * klass)
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
|
gobject_class->finalize = gst_rtph263pdec_finalize;
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtph263pdec_set_property;
|
gobject_class->set_property = gst_rtph263pdec_set_property;
|
||||||
gobject_class->get_property = gst_rtph263pdec_get_property;
|
gobject_class->get_property = gst_rtph263pdec_get_property;
|
||||||
|
|
||||||
|
@ -145,6 +151,19 @@ gst_rtph263pdec_init (GstRtpH263PDec * rtph263pdec)
|
||||||
rtph263pdec->adapter = gst_adapter_new ();
|
rtph263pdec->adapter = gst_adapter_new ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtph263pdec_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
GstRtpH263PDec *rtph263pdec;
|
||||||
|
|
||||||
|
rtph263pdec = GST_RTP_H263P_DEC (object);
|
||||||
|
|
||||||
|
g_object_unref (rtph263pdec->adapter);
|
||||||
|
rtph263pdec->adapter = NULL;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtph263pdec_chain (GstPad * pad, GstBuffer * buf)
|
gst_rtph263pdec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
@ -292,6 +311,9 @@ gst_rtph263pdec_change_state (GstElement * element, GstStateChange transition)
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
|
gst_adapter_clear (rtph263pdec->adapter);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,29 +26,10 @@
|
||||||
static GstElementDetails gst_rtp_h263penc_details = {
|
static GstElementDetails gst_rtp_h263penc_details = {
|
||||||
"RTP packet parser",
|
"RTP packet parser",
|
||||||
"Codec/Parser/Network",
|
"Codec/Parser/Network",
|
||||||
"Extracts H263+ video from RTP packets",
|
"Encodes H263+ video in RTP packets (RFC 2429)",
|
||||||
"Wim Taymans <wim@fluendo.com>"
|
"Wim Taymans <wim@fluendo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RtpH263PEnc signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DEFAULT_MTU 1024
|
|
||||||
#define DEFAULT_PT 96
|
|
||||||
#define DEFAULT_SSRC 0
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_MTU,
|
|
||||||
PROP_PT,
|
|
||||||
PROP_SSRC
|
|
||||||
};
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtph263penc_sink_template =
|
static GstStaticPadTemplate gst_rtph263penc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -60,25 +41,23 @@ static GstStaticPadTemplate gst_rtph263penc_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp")
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"video\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 90000, " "encoding_name = (string) \"H263-1998\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void gst_rtph263penc_class_init (GstRtpH263PEncClass * klass);
|
static void gst_rtph263penc_class_init (GstRtpH263PEncClass * klass);
|
||||||
static void gst_rtph263penc_base_init (GstRtpH263PEncClass * klass);
|
static void gst_rtph263penc_base_init (GstRtpH263PEncClass * klass);
|
||||||
static void gst_rtph263penc_init (GstRtpH263PEnc * rtph263penc);
|
static void gst_rtph263penc_init (GstRtpH263PEnc * rtph263penc);
|
||||||
|
static void gst_rtph263penc_finalize (GObject * object);
|
||||||
|
|
||||||
static GstFlowReturn gst_rtph263penc_chain (GstPad * pad, GstBuffer * buffer);
|
static gboolean gst_rtph263penc_setcaps (GstBaseRTPPayload * payload,
|
||||||
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_rtph263penc_handle_buffer (GstBaseRTPPayload * payload,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
static void gst_rtph263penc_set_property (GObject * object, guint prop_id,
|
static GstBaseRTPPayloadClass *parent_class = NULL;
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_rtph263penc_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
|
|
||||||
static GstStateChangeReturn gst_rtph263penc_change_state (GstElement *
|
|
||||||
element, GstStateChange transition);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gst_rtph263penc_get_type (void)
|
gst_rtph263penc_get_type (void)
|
||||||
|
@ -99,7 +78,7 @@ gst_rtph263penc_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
rtph263penc_type =
|
rtph263penc_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRtpH263PEnc",
|
g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpH263PEnc",
|
||||||
&rtph263penc_info, 0);
|
&rtph263penc_info, 0);
|
||||||
}
|
}
|
||||||
return rtph263penc_type;
|
return rtph263penc_type;
|
||||||
|
@ -123,49 +102,49 @@ gst_rtph263penc_class_init (GstRtpH263PEncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtph263penc_set_property;
|
gobject_class->finalize = gst_rtph263penc_finalize;
|
||||||
gobject_class->get_property = gst_rtph263penc_get_property;
|
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
|
gstbasertppayload_class->set_caps = gst_rtph263penc_setcaps;
|
||||||
g_param_spec_uint ("mtu", "MTU",
|
gstbasertppayload_class->handle_buffer = gst_rtph263penc_handle_buffer;
|
||||||
"Maximum size of one packet",
|
|
||||||
28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
|
|
||||||
g_param_spec_uint ("pt", "payload type",
|
|
||||||
"The payload type of the packets",
|
|
||||||
0, 0x80, DEFAULT_PT, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
|
|
||||||
g_param_spec_uint ("ssrc", "SSRC",
|
|
||||||
"The SSRC of the packets",
|
|
||||||
0, G_MAXUINT, DEFAULT_SSRC, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtph263penc_change_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtph263penc_init (GstRtpH263PEnc * rtph263penc)
|
gst_rtph263penc_init (GstRtpH263PEnc * rtph263penc)
|
||||||
{
|
{
|
||||||
rtph263penc->srcpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtph263penc_src_template), "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtph263penc), rtph263penc->srcpad);
|
|
||||||
|
|
||||||
rtph263penc->sinkpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtph263penc_sink_template), "sink");
|
|
||||||
gst_pad_set_chain_function (rtph263penc->sinkpad, gst_rtph263penc_chain);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtph263penc), rtph263penc->sinkpad);
|
|
||||||
|
|
||||||
rtph263penc->adapter = gst_adapter_new ();
|
rtph263penc->adapter = gst_adapter_new ();
|
||||||
rtph263penc->mtu = DEFAULT_MTU;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtph263penc_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
GstRtpH263PEnc *rtph263penc;
|
||||||
|
|
||||||
|
rtph263penc = GST_RTP_H263P_ENC (object);
|
||||||
|
|
||||||
|
g_object_unref (rtph263penc->adapter);
|
||||||
|
rtph263penc->adapter = NULL;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtph263penc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
|
||||||
|
{
|
||||||
|
gst_basertppayload_set_options (payload, "video", TRUE, "H263-1998", 90000);
|
||||||
|
gst_basertppayload_set_outcaps (payload, NULL);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
||||||
{
|
{
|
||||||
|
@ -189,7 +168,7 @@ gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
||||||
|
|
||||||
/* FIXME, do better mtu packing, header len etc should be
|
/* FIXME, do better mtu packing, header len etc should be
|
||||||
* included in this calculation. */
|
* included in this calculation. */
|
||||||
towrite = MIN (avail, rtph263penc->mtu);
|
towrite = MIN (avail, GST_BASE_RTP_PAYLOAD_MTU (rtph263penc));
|
||||||
/* for fragmented frames we need 2 bytes header, for other
|
/* for fragmented frames we need 2 bytes header, for other
|
||||||
* frames we must reuse the first 2 bytes of the data as the
|
* frames we must reuse the first 2 bytes of the data as the
|
||||||
* header */
|
* header */
|
||||||
|
@ -197,11 +176,6 @@ gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
||||||
payload_len = header_len + towrite;
|
payload_len = header_len + towrite;
|
||||||
|
|
||||||
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
||||||
gst_rtpbuffer_set_timestamp (outbuf,
|
|
||||||
rtph263penc->first_ts * 90000 / GST_SECOND);
|
|
||||||
gst_rtpbuffer_set_payload_type (outbuf, rtph263penc->pt);
|
|
||||||
gst_rtpbuffer_set_ssrc (outbuf, rtph263penc->ssrc);
|
|
||||||
gst_rtpbuffer_set_seq (outbuf, rtph263penc->seqnum++);
|
|
||||||
/* last fragment gets the marker bit set */
|
/* last fragment gets the marker bit set */
|
||||||
gst_rtpbuffer_set_marker (outbuf, avail > towrite ? 0 : 1);
|
gst_rtpbuffer_set_marker (outbuf, avail > towrite ? 0 : 1);
|
||||||
|
|
||||||
|
@ -222,7 +196,7 @@ gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = rtph263penc->first_ts;
|
GST_BUFFER_TIMESTAMP (outbuf) = rtph263penc->first_ts;
|
||||||
gst_adapter_flush (rtph263penc->adapter, towrite);
|
gst_adapter_flush (rtph263penc->adapter, towrite);
|
||||||
|
|
||||||
ret = gst_pad_push (rtph263penc->srcpad, outbuf);
|
ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtph263penc), outbuf);
|
||||||
|
|
||||||
avail -= towrite;
|
avail -= towrite;
|
||||||
fragmented = TRUE;
|
fragmented = TRUE;
|
||||||
|
@ -232,13 +206,13 @@ gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtph263penc_chain (GstPad * pad, GstBuffer * buffer)
|
gst_rtph263penc_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstRtpH263PEnc *rtph263penc;
|
GstRtpH263PEnc *rtph263penc;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
guint size;
|
guint size;
|
||||||
|
|
||||||
rtph263penc = GST_RTP_H263P_ENC (GST_OBJECT_PARENT (pad));
|
rtph263penc = GST_RTP_H263P_ENC (payload);
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (buffer);
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
rtph263penc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
rtph263penc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
@ -250,80 +224,6 @@ gst_rtph263penc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtph263penc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpH263PEnc *rtph263penc;
|
|
||||||
|
|
||||||
rtph263penc = GST_RTP_H263P_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
rtph263penc->mtu = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
rtph263penc->pt = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
rtph263penc->ssrc = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtph263penc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpH263PEnc *rtph263penc;
|
|
||||||
|
|
||||||
rtph263penc = GST_RTP_H263P_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
g_value_set_uint (value, rtph263penc->mtu);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
g_value_set_uint (value, rtph263penc->pt);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
g_value_set_uint (value, rtph263penc->ssrc);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_rtph263penc_change_state (GstElement * element, GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstRtpH263PEnc *rtph263penc;
|
|
||||||
GstStateChangeReturn ret;
|
|
||||||
|
|
||||||
rtph263penc = GST_RTP_H263P_ENC (element);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_rtph263penc_plugin_init (GstPlugin * plugin)
|
gst_rtph263penc_plugin_init (GstPlugin * plugin)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define __GST_RTP_H263P_ENC_H__
|
#define __GST_RTP_H263P_ENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/rtp/gstbasertppayload.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -41,24 +42,15 @@ typedef struct _GstRtpH263PEncClass GstRtpH263PEncClass;
|
||||||
|
|
||||||
struct _GstRtpH263PEnc
|
struct _GstRtpH263PEnc
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstBaseRTPPayload payload;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
GstAdapter *adapter;
|
GstAdapter *adapter;
|
||||||
GstClockTime first_ts;
|
GstClockTime first_ts;
|
||||||
|
|
||||||
guint16 seqnum;
|
|
||||||
guint pt;
|
|
||||||
guint ssrc;
|
|
||||||
|
|
||||||
guint mtu;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstRtpH263PEncClass
|
struct _GstRtpH263PEncClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstBaseRTPPayloadClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
gboolean gst_rtph263penc_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtph263penc_plugin_init (GstPlugin * plugin);
|
||||||
|
|
|
@ -26,29 +26,10 @@
|
||||||
static GstElementDetails gst_rtp_h263penc_details = {
|
static GstElementDetails gst_rtp_h263penc_details = {
|
||||||
"RTP packet parser",
|
"RTP packet parser",
|
||||||
"Codec/Parser/Network",
|
"Codec/Parser/Network",
|
||||||
"Extracts H263+ video from RTP packets",
|
"Encodes H263+ video in RTP packets (RFC 2429)",
|
||||||
"Wim Taymans <wim@fluendo.com>"
|
"Wim Taymans <wim@fluendo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RtpH263PEnc signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DEFAULT_MTU 1024
|
|
||||||
#define DEFAULT_PT 96
|
|
||||||
#define DEFAULT_SSRC 0
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_MTU,
|
|
||||||
PROP_PT,
|
|
||||||
PROP_SSRC
|
|
||||||
};
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtph263penc_sink_template =
|
static GstStaticPadTemplate gst_rtph263penc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -60,25 +41,23 @@ static GstStaticPadTemplate gst_rtph263penc_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp")
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"video\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 90000, " "encoding_name = (string) \"H263-1998\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void gst_rtph263penc_class_init (GstRtpH263PEncClass * klass);
|
static void gst_rtph263penc_class_init (GstRtpH263PEncClass * klass);
|
||||||
static void gst_rtph263penc_base_init (GstRtpH263PEncClass * klass);
|
static void gst_rtph263penc_base_init (GstRtpH263PEncClass * klass);
|
||||||
static void gst_rtph263penc_init (GstRtpH263PEnc * rtph263penc);
|
static void gst_rtph263penc_init (GstRtpH263PEnc * rtph263penc);
|
||||||
|
static void gst_rtph263penc_finalize (GObject * object);
|
||||||
|
|
||||||
static GstFlowReturn gst_rtph263penc_chain (GstPad * pad, GstBuffer * buffer);
|
static gboolean gst_rtph263penc_setcaps (GstBaseRTPPayload * payload,
|
||||||
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_rtph263penc_handle_buffer (GstBaseRTPPayload * payload,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
static void gst_rtph263penc_set_property (GObject * object, guint prop_id,
|
static GstBaseRTPPayloadClass *parent_class = NULL;
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_rtph263penc_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
|
|
||||||
static GstStateChangeReturn gst_rtph263penc_change_state (GstElement *
|
|
||||||
element, GstStateChange transition);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gst_rtph263penc_get_type (void)
|
gst_rtph263penc_get_type (void)
|
||||||
|
@ -99,7 +78,7 @@ gst_rtph263penc_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
rtph263penc_type =
|
rtph263penc_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRtpH263PEnc",
|
g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpH263PEnc",
|
||||||
&rtph263penc_info, 0);
|
&rtph263penc_info, 0);
|
||||||
}
|
}
|
||||||
return rtph263penc_type;
|
return rtph263penc_type;
|
||||||
|
@ -123,49 +102,49 @@ gst_rtph263penc_class_init (GstRtpH263PEncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtph263penc_set_property;
|
gobject_class->finalize = gst_rtph263penc_finalize;
|
||||||
gobject_class->get_property = gst_rtph263penc_get_property;
|
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
|
gstbasertppayload_class->set_caps = gst_rtph263penc_setcaps;
|
||||||
g_param_spec_uint ("mtu", "MTU",
|
gstbasertppayload_class->handle_buffer = gst_rtph263penc_handle_buffer;
|
||||||
"Maximum size of one packet",
|
|
||||||
28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
|
|
||||||
g_param_spec_uint ("pt", "payload type",
|
|
||||||
"The payload type of the packets",
|
|
||||||
0, 0x80, DEFAULT_PT, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
|
|
||||||
g_param_spec_uint ("ssrc", "SSRC",
|
|
||||||
"The SSRC of the packets",
|
|
||||||
0, G_MAXUINT, DEFAULT_SSRC, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtph263penc_change_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtph263penc_init (GstRtpH263PEnc * rtph263penc)
|
gst_rtph263penc_init (GstRtpH263PEnc * rtph263penc)
|
||||||
{
|
{
|
||||||
rtph263penc->srcpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtph263penc_src_template), "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtph263penc), rtph263penc->srcpad);
|
|
||||||
|
|
||||||
rtph263penc->sinkpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtph263penc_sink_template), "sink");
|
|
||||||
gst_pad_set_chain_function (rtph263penc->sinkpad, gst_rtph263penc_chain);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtph263penc), rtph263penc->sinkpad);
|
|
||||||
|
|
||||||
rtph263penc->adapter = gst_adapter_new ();
|
rtph263penc->adapter = gst_adapter_new ();
|
||||||
rtph263penc->mtu = DEFAULT_MTU;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtph263penc_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
GstRtpH263PEnc *rtph263penc;
|
||||||
|
|
||||||
|
rtph263penc = GST_RTP_H263P_ENC (object);
|
||||||
|
|
||||||
|
g_object_unref (rtph263penc->adapter);
|
||||||
|
rtph263penc->adapter = NULL;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtph263penc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
|
||||||
|
{
|
||||||
|
gst_basertppayload_set_options (payload, "video", TRUE, "H263-1998", 90000);
|
||||||
|
gst_basertppayload_set_outcaps (payload, NULL);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
||||||
{
|
{
|
||||||
|
@ -189,7 +168,7 @@ gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
||||||
|
|
||||||
/* FIXME, do better mtu packing, header len etc should be
|
/* FIXME, do better mtu packing, header len etc should be
|
||||||
* included in this calculation. */
|
* included in this calculation. */
|
||||||
towrite = MIN (avail, rtph263penc->mtu);
|
towrite = MIN (avail, GST_BASE_RTP_PAYLOAD_MTU (rtph263penc));
|
||||||
/* for fragmented frames we need 2 bytes header, for other
|
/* for fragmented frames we need 2 bytes header, for other
|
||||||
* frames we must reuse the first 2 bytes of the data as the
|
* frames we must reuse the first 2 bytes of the data as the
|
||||||
* header */
|
* header */
|
||||||
|
@ -197,11 +176,6 @@ gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
||||||
payload_len = header_len + towrite;
|
payload_len = header_len + towrite;
|
||||||
|
|
||||||
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
||||||
gst_rtpbuffer_set_timestamp (outbuf,
|
|
||||||
rtph263penc->first_ts * 90000 / GST_SECOND);
|
|
||||||
gst_rtpbuffer_set_payload_type (outbuf, rtph263penc->pt);
|
|
||||||
gst_rtpbuffer_set_ssrc (outbuf, rtph263penc->ssrc);
|
|
||||||
gst_rtpbuffer_set_seq (outbuf, rtph263penc->seqnum++);
|
|
||||||
/* last fragment gets the marker bit set */
|
/* last fragment gets the marker bit set */
|
||||||
gst_rtpbuffer_set_marker (outbuf, avail > towrite ? 0 : 1);
|
gst_rtpbuffer_set_marker (outbuf, avail > towrite ? 0 : 1);
|
||||||
|
|
||||||
|
@ -222,7 +196,7 @@ gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = rtph263penc->first_ts;
|
GST_BUFFER_TIMESTAMP (outbuf) = rtph263penc->first_ts;
|
||||||
gst_adapter_flush (rtph263penc->adapter, towrite);
|
gst_adapter_flush (rtph263penc->adapter, towrite);
|
||||||
|
|
||||||
ret = gst_pad_push (rtph263penc->srcpad, outbuf);
|
ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtph263penc), outbuf);
|
||||||
|
|
||||||
avail -= towrite;
|
avail -= towrite;
|
||||||
fragmented = TRUE;
|
fragmented = TRUE;
|
||||||
|
@ -232,13 +206,13 @@ gst_rtph263penc_flush (GstRtpH263PEnc * rtph263penc)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtph263penc_chain (GstPad * pad, GstBuffer * buffer)
|
gst_rtph263penc_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstRtpH263PEnc *rtph263penc;
|
GstRtpH263PEnc *rtph263penc;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
guint size;
|
guint size;
|
||||||
|
|
||||||
rtph263penc = GST_RTP_H263P_ENC (GST_OBJECT_PARENT (pad));
|
rtph263penc = GST_RTP_H263P_ENC (payload);
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (buffer);
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
rtph263penc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
rtph263penc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
@ -250,80 +224,6 @@ gst_rtph263penc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtph263penc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpH263PEnc *rtph263penc;
|
|
||||||
|
|
||||||
rtph263penc = GST_RTP_H263P_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
rtph263penc->mtu = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
rtph263penc->pt = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
rtph263penc->ssrc = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtph263penc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpH263PEnc *rtph263penc;
|
|
||||||
|
|
||||||
rtph263penc = GST_RTP_H263P_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
g_value_set_uint (value, rtph263penc->mtu);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
g_value_set_uint (value, rtph263penc->pt);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
g_value_set_uint (value, rtph263penc->ssrc);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_rtph263penc_change_state (GstElement * element, GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstRtpH263PEnc *rtph263penc;
|
|
||||||
GstStateChangeReturn ret;
|
|
||||||
|
|
||||||
rtph263penc = GST_RTP_H263P_ENC (element);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_rtph263penc_plugin_init (GstPlugin * plugin)
|
gst_rtph263penc_plugin_init (GstPlugin * plugin)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define __GST_RTP_H263P_ENC_H__
|
#define __GST_RTP_H263P_ENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/rtp/gstbasertppayload.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -41,24 +42,15 @@ typedef struct _GstRtpH263PEncClass GstRtpH263PEncClass;
|
||||||
|
|
||||||
struct _GstRtpH263PEnc
|
struct _GstRtpH263PEnc
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstBaseRTPPayload payload;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
GstAdapter *adapter;
|
GstAdapter *adapter;
|
||||||
GstClockTime first_ts;
|
GstClockTime first_ts;
|
||||||
|
|
||||||
guint16 seqnum;
|
|
||||||
guint pt;
|
|
||||||
guint ssrc;
|
|
||||||
|
|
||||||
guint mtu;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstRtpH263PEncClass
|
struct _GstRtpH263PEncClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstBaseRTPPayloadClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
gboolean gst_rtph263penc_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtph263penc_plugin_init (GstPlugin * plugin);
|
||||||
|
|
|
@ -54,10 +54,12 @@ static GstStaticPadTemplate gst_rtpmp4vdec_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp"
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"video\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) [1, MAX ], " "encoding_name = (string) \"MP4V-ES\""
|
||||||
/* All optional parameters
|
/* All optional parameters
|
||||||
*
|
*
|
||||||
* "rate=(int) [1, MAX],"
|
|
||||||
* "profile-level-id=[1,MAX]"
|
* "profile-level-id=[1,MAX]"
|
||||||
* "config="
|
* "config="
|
||||||
*/
|
*/
|
||||||
|
@ -164,7 +166,7 @@ gst_rtpmp4vdec_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
|
|
||||||
structure = gst_caps_get_structure (caps, 0);
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
if (!gst_structure_get_int (structure, "rate", &rtpmp4vdec->rate))
|
if (!gst_structure_get_int (structure, "clock_rate", &rtpmp4vdec->rate))
|
||||||
rtpmp4vdec->rate = 90000;
|
rtpmp4vdec->rate = 90000;
|
||||||
|
|
||||||
srccaps = gst_caps_new_simple ("video/mpeg",
|
srccaps = gst_caps_new_simple ("video/mpeg",
|
||||||
|
@ -282,7 +284,6 @@ gst_rtpmp4vdec_change_state (GstElement * element, GstStateChange transition)
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
gst_adapter_clear (rtpmp4vdec->adapter);
|
gst_adapter_clear (rtpmp4vdec->adapter);
|
||||||
rtpmp4vdec->rate = 90000;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -54,10 +54,12 @@ static GstStaticPadTemplate gst_rtpmp4vdec_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp"
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"video\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) [1, MAX ], " "encoding_name = (string) \"MP4V-ES\""
|
||||||
/* All optional parameters
|
/* All optional parameters
|
||||||
*
|
*
|
||||||
* "rate=(int) [1, MAX],"
|
|
||||||
* "profile-level-id=[1,MAX]"
|
* "profile-level-id=[1,MAX]"
|
||||||
* "config="
|
* "config="
|
||||||
*/
|
*/
|
||||||
|
@ -164,7 +166,7 @@ gst_rtpmp4vdec_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
|
|
||||||
structure = gst_caps_get_structure (caps, 0);
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
if (!gst_structure_get_int (structure, "rate", &rtpmp4vdec->rate))
|
if (!gst_structure_get_int (structure, "clock_rate", &rtpmp4vdec->rate))
|
||||||
rtpmp4vdec->rate = 90000;
|
rtpmp4vdec->rate = 90000;
|
||||||
|
|
||||||
srccaps = gst_caps_new_simple ("video/mpeg",
|
srccaps = gst_caps_new_simple ("video/mpeg",
|
||||||
|
@ -282,7 +284,6 @@ gst_rtpmp4vdec_change_state (GstElement * element, GstStateChange transition)
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
gst_adapter_clear (rtpmp4vdec->adapter);
|
gst_adapter_clear (rtpmp4vdec->adapter);
|
||||||
rtpmp4vdec->rate = 90000;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -30,25 +30,6 @@ static GstElementDetails gst_rtp_mp4venc_details = {
|
||||||
"Wim Taymans <wim@fluendo.com>"
|
"Wim Taymans <wim@fluendo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RtpMP4VEnc signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DEFAULT_MTU 1024
|
|
||||||
#define DEFAULT_PT 96
|
|
||||||
#define DEFAULT_SSRC 0
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_MTU,
|
|
||||||
PROP_PT,
|
|
||||||
PROP_SSRC
|
|
||||||
};
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtpmp4venc_sink_template =
|
static GstStaticPadTemplate gst_rtpmp4venc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -61,9 +42,15 @@ static GstStaticPadTemplate gst_rtpmp4venc_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp,"
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
"rate=(int) [1, MAX]," "profile-level-id=[1,MAX]"
|
"media = (string) \"video\", "
|
||||||
/* "config=" */
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) [1, MAX ], "
|
||||||
|
"encoding_name = (string) \"MP4V-ES\", " "profile-level-id=[1,MAX]"
|
||||||
|
/* All optional parameters
|
||||||
|
*
|
||||||
|
* "config="
|
||||||
|
*/
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -71,19 +58,14 @@ GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
static void gst_rtpmp4venc_class_init (GstRtpMP4VEncClass * klass);
|
static void gst_rtpmp4venc_class_init (GstRtpMP4VEncClass * klass);
|
||||||
static void gst_rtpmp4venc_base_init (GstRtpMP4VEncClass * klass);
|
static void gst_rtpmp4venc_base_init (GstRtpMP4VEncClass * klass);
|
||||||
static void gst_rtpmp4venc_init (GstRtpMP4VEnc * rtpmp4venc);
|
static void gst_rtpmp4venc_init (GstRtpMP4VEnc * rtpmp4venc);
|
||||||
|
static void gst_rtpmp4venc_finalize (GObject * object);
|
||||||
|
|
||||||
static gboolean gst_rtpmp4venc_setcaps (GstPad * pad, GstCaps * caps);
|
static gboolean gst_rtpmp4venc_setcaps (GstBaseRTPPayload * payload,
|
||||||
static GstFlowReturn gst_rtpmp4venc_chain (GstPad * pad, GstBuffer * buffer);
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_rtpmp4venc_handle_buffer (GstBaseRTPPayload * payload,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
static void gst_rtpmp4venc_set_property (GObject * object, guint prop_id,
|
static GstBaseRTPPayloadClass *parent_class = NULL;
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_rtpmp4venc_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
|
|
||||||
static GstStateChangeReturn gst_rtpmp4venc_change_state (GstElement * element,
|
|
||||||
GstStateChange transition);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gst_rtpmp4venc_get_type (void)
|
gst_rtpmp4venc_get_type (void)
|
||||||
|
@ -104,7 +86,7 @@ gst_rtpmp4venc_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
rtpmp4venc_type =
|
rtpmp4venc_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRtpMP4VEnc",
|
g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpMP4VEnc",
|
||||||
&rtpmp4venc_info, 0);
|
&rtpmp4venc_info, 0);
|
||||||
}
|
}
|
||||||
return rtpmp4venc_type;
|
return rtpmp4venc_type;
|
||||||
|
@ -128,69 +110,58 @@ gst_rtpmp4venc_class_init (GstRtpMP4VEncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtpmp4venc_set_property;
|
gobject_class->finalize = gst_rtpmp4venc_finalize;
|
||||||
gobject_class->get_property = gst_rtpmp4venc_get_property;
|
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
|
gstbasertppayload_class->set_caps = gst_rtpmp4venc_setcaps;
|
||||||
g_param_spec_uint ("mtu", "MTU",
|
gstbasertppayload_class->handle_buffer = gst_rtpmp4venc_handle_buffer;
|
||||||
"Maximum size of one packet",
|
|
||||||
28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
|
|
||||||
g_param_spec_uint ("pt", "payload type",
|
|
||||||
"The payload type of the packets",
|
|
||||||
0, 0x80, DEFAULT_PT, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
|
|
||||||
g_param_spec_uint ("ssrc", "SSRC",
|
|
||||||
"The SSRC of the packets",
|
|
||||||
0, G_MAXUINT, DEFAULT_SSRC, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtpmp4venc_change_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtpmp4venc_init (GstRtpMP4VEnc * rtpmp4venc)
|
gst_rtpmp4venc_init (GstRtpMP4VEnc * rtpmp4venc)
|
||||||
{
|
{
|
||||||
rtpmp4venc->srcpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpmp4venc_src_template), "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpmp4venc), rtpmp4venc->srcpad);
|
|
||||||
|
|
||||||
rtpmp4venc->sinkpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpmp4venc_sink_template), "sink");
|
|
||||||
gst_pad_set_setcaps_function (rtpmp4venc->sinkpad, gst_rtpmp4venc_setcaps);
|
|
||||||
gst_pad_set_chain_function (rtpmp4venc->sinkpad, gst_rtpmp4venc_chain);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpmp4venc), rtpmp4venc->sinkpad);
|
|
||||||
|
|
||||||
rtpmp4venc->adapter = gst_adapter_new ();
|
rtpmp4venc->adapter = gst_adapter_new ();
|
||||||
rtpmp4venc->mtu = DEFAULT_MTU;
|
|
||||||
rtpmp4venc->pt = DEFAULT_PT;
|
|
||||||
rtpmp4venc->ssrc = DEFAULT_SSRC;
|
|
||||||
rtpmp4venc->rate = 90000;
|
rtpmp4venc->rate = 90000;
|
||||||
rtpmp4venc->profile = 1;
|
rtpmp4venc->profile = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_rtpmp4venc_setcaps (GstPad * pad, GstCaps * caps)
|
gst_rtpmp4venc_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstRtpMP4VEnc *rtpmp4venc;
|
GstRtpMP4VEnc *rtpmp4venc;
|
||||||
GstCaps *srccaps;
|
|
||||||
|
|
||||||
rtpmp4venc = GST_RTP_MP4V_ENC (gst_pad_get_parent (pad));
|
rtpmp4venc = GST_RTP_MP4V_ENC (object);
|
||||||
|
|
||||||
srccaps = gst_caps_new_simple ("application/x-rtp",
|
g_object_unref (rtpmp4venc->adapter);
|
||||||
"rate", G_TYPE_INT, rtpmp4venc->rate,
|
rtpmp4venc->adapter = NULL;
|
||||||
"profile-level-id", G_TYPE_INT, rtpmp4venc->profile, NULL);
|
|
||||||
gst_pad_set_caps (rtpmp4venc->srcpad, srccaps);
|
|
||||||
gst_caps_unref (srccaps);
|
|
||||||
|
|
||||||
gst_object_unref (rtpmp4venc);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtpmp4venc_new_caps (GstRtpMP4VEnc * rtpmp4venc)
|
||||||
|
{
|
||||||
|
gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4venc),
|
||||||
|
"profile-level-id", G_TYPE_INT, rtpmp4venc->profile,
|
||||||
|
"config", GST_TYPE_BUFFER, rtpmp4venc->config, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtpmp4venc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
|
||||||
|
{
|
||||||
|
GstRtpMP4VEnc *rtpmp4venc;
|
||||||
|
|
||||||
|
rtpmp4venc = GST_RTP_MP4V_ENC (payload);
|
||||||
|
|
||||||
|
gst_basertppayload_set_options (payload, "video", TRUE, "MP4V-ES",
|
||||||
|
rtpmp4venc->rate);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -201,7 +172,6 @@ gst_rtpmp4venc_flush (GstRtpMP4VEnc * rtpmp4venc)
|
||||||
guint avail;
|
guint avail;
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
guint16 frag_offset;
|
|
||||||
|
|
||||||
/* the data available in the adapter is either smaller
|
/* the data available in the adapter is either smaller
|
||||||
* than the MTU or bigger. In the case it is smaller, the complete
|
* than the MTU or bigger. In the case it is smaller, the complete
|
||||||
|
@ -212,7 +182,6 @@ gst_rtpmp4venc_flush (GstRtpMP4VEnc * rtpmp4venc)
|
||||||
|
|
||||||
ret = GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
|
|
||||||
frag_offset = 0;
|
|
||||||
while (avail > 0) {
|
while (avail > 0) {
|
||||||
guint towrite;
|
guint towrite;
|
||||||
guint8 *payload;
|
guint8 *payload;
|
||||||
|
@ -224,159 +193,149 @@ gst_rtpmp4venc_flush (GstRtpMP4VEnc * rtpmp4venc)
|
||||||
packet_len = gst_rtpbuffer_calc_packet_len (avail, 0, 0);
|
packet_len = gst_rtpbuffer_calc_packet_len (avail, 0, 0);
|
||||||
|
|
||||||
/* fill one MTU or all available bytes */
|
/* fill one MTU or all available bytes */
|
||||||
towrite = MIN (packet_len, rtpmp4venc->mtu);
|
towrite = MIN (packet_len, GST_BASE_RTP_PAYLOAD_MTU (rtpmp4venc));
|
||||||
|
|
||||||
/* this is the payload length */
|
/* this is the payload length */
|
||||||
payload_len = gst_rtpbuffer_calc_payload_len (towrite, 0, 0);
|
payload_len = gst_rtpbuffer_calc_payload_len (towrite, 0, 0);
|
||||||
|
|
||||||
/* create buffer to hold the payload */
|
/* create buffer to hold the payload */
|
||||||
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
||||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpmp4venc->srcpad));
|
|
||||||
|
|
||||||
/* set timestamp */
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (rtpmp4venc->first_ts)) {
|
|
||||||
gst_rtpbuffer_set_timestamp (outbuf,
|
|
||||||
rtpmp4venc->first_ts * 90000 / GST_SECOND);
|
|
||||||
}
|
|
||||||
gst_rtpbuffer_set_payload_type (outbuf, rtpmp4venc->pt);
|
|
||||||
gst_rtpbuffer_set_seq (outbuf, rtpmp4venc->seqnum++);
|
|
||||||
|
|
||||||
|
/* copy payload */
|
||||||
payload = gst_rtpbuffer_get_payload (outbuf);
|
payload = gst_rtpbuffer_get_payload (outbuf);
|
||||||
|
|
||||||
data = (guint8 *) gst_adapter_peek (rtpmp4venc->adapter, payload_len);
|
data = (guint8 *) gst_adapter_peek (rtpmp4venc->adapter, payload_len);
|
||||||
memcpy (payload, data, payload_len);
|
memcpy (payload, data, payload_len);
|
||||||
|
|
||||||
gst_adapter_flush (rtpmp4venc->adapter, payload_len);
|
gst_adapter_flush (rtpmp4venc->adapter, payload_len);
|
||||||
|
|
||||||
avail -= payload_len;
|
avail -= payload_len;
|
||||||
frag_offset += payload_len;
|
|
||||||
|
|
||||||
gst_rtpbuffer_set_marker (outbuf, avail == 0);
|
gst_rtpbuffer_set_marker (outbuf, avail == 0);
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4venc->first_ts;
|
GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4venc->first_ts;
|
||||||
|
|
||||||
ret = gst_pad_push (rtpmp4venc->srcpad, outbuf);
|
ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmp4venc), outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define VOS_STARTCODE 0x000001B0
|
||||||
|
#define VOS_ENDCODE 0x000001B1
|
||||||
|
#define USER_DATA_STARTCODE 0x000001B2
|
||||||
|
#define GOP_STARTCODE 0x000001B3
|
||||||
|
#define VISUAL_OBJECT_STARTCODE 0x000001B5
|
||||||
|
#define VOP_STARTCODE 0x000001B6
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtpmp4venc_parse_data (GstRtpMP4VEnc * enc, guint8 * data, guint size)
|
||||||
|
{
|
||||||
|
guint32 code;
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
|
if (size < 5)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
code = GST_READ_UINT32_BE (data);
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case VOS_STARTCODE:
|
||||||
|
{
|
||||||
|
gint i;
|
||||||
|
guint8 profile;
|
||||||
|
gboolean newprofile = FALSE;
|
||||||
|
gboolean equal;
|
||||||
|
|
||||||
|
/* profile_and_level_indication */
|
||||||
|
profile = data[4];
|
||||||
|
|
||||||
|
if (profile != enc->profile) {
|
||||||
|
newprofile = TRUE;
|
||||||
|
enc->profile = profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* up to the next GOP_STARTCODE or VOP_STARTCODE is
|
||||||
|
* the config information */
|
||||||
|
code = 0xffffffff;
|
||||||
|
for (i = 5; i < size - 4; i++) {
|
||||||
|
code = (code << 8) | data[i];
|
||||||
|
if (code == GOP_STARTCODE || code == VOP_STARTCODE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i -= 3;
|
||||||
|
/* see if config changed */
|
||||||
|
equal = FALSE;
|
||||||
|
if (enc->config) {
|
||||||
|
if (GST_BUFFER_SIZE (enc->config) == i) {
|
||||||
|
equal = memcmp (GST_BUFFER_DATA (enc->config), data, i) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if config string changed or new profile, make new caps */
|
||||||
|
if (!equal || newprofile) {
|
||||||
|
if (enc->config)
|
||||||
|
gst_buffer_unref (enc->config);
|
||||||
|
enc->config = gst_buffer_new_and_alloc (i);
|
||||||
|
memcpy (GST_BUFFER_DATA (enc->config), data, i);
|
||||||
|
gst_rtpmp4venc_new_caps (enc);
|
||||||
|
}
|
||||||
|
result = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VOP_STARTCODE:
|
||||||
|
result = FALSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* we expect buffers starting on startcodes.
|
/* we expect buffers starting on startcodes.
|
||||||
*
|
|
||||||
* FIXME, need to flush the adapter if we receive non VOP
|
|
||||||
* packets.
|
|
||||||
*/
|
*/
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtpmp4venc_chain (GstPad * pad, GstBuffer * buffer)
|
gst_rtpmp4venc_handle_buffer (GstBaseRTPPayload * basepayload,
|
||||||
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstRtpMP4VEnc *rtpmp4venc;
|
GstRtpMP4VEnc *rtpmp4venc;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
guint size, avail;
|
guint size, avail;
|
||||||
guint packet_len;
|
guint packet_len;
|
||||||
|
guint8 *data;
|
||||||
|
gboolean flush;
|
||||||
|
|
||||||
rtpmp4venc = GST_RTP_MP4V_ENC (gst_pad_get_parent (pad));
|
rtpmp4venc = GST_RTP_MP4V_ENC (basepayload);
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (buffer);
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
|
data = GST_BUFFER_DATA (buffer);
|
||||||
avail = gst_adapter_available (rtpmp4venc->adapter);
|
avail = gst_adapter_available (rtpmp4venc->adapter);
|
||||||
|
|
||||||
|
/* parse incomming data and see if we need to start a new RTP
|
||||||
|
* packet */
|
||||||
|
flush = gst_rtpmp4venc_parse_data (rtpmp4venc, data, size);
|
||||||
|
|
||||||
/* get packet length of previous data and this new data */
|
/* get packet length of previous data and this new data */
|
||||||
packet_len = gst_rtpbuffer_calc_packet_len (avail + size, 0, 0);
|
packet_len = gst_rtpbuffer_calc_packet_len (avail + size, 0, 0);
|
||||||
|
|
||||||
/* if this buffer is going to overflow the packet, flush what we
|
/* if this buffer is going to overflow the packet, flush what we
|
||||||
* have. */
|
* have. */
|
||||||
if (packet_len > rtpmp4venc->mtu) {
|
if (flush || packet_len > GST_BASE_RTP_PAYLOAD_MTU (rtpmp4venc)) {
|
||||||
ret = gst_rtpmp4venc_flush (rtpmp4venc);
|
ret = gst_rtpmp4venc_flush (rtpmp4venc);
|
||||||
avail = 0;
|
avail = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_adapter_push (rtpmp4venc->adapter, buffer);
|
gst_adapter_push (rtpmp4venc->adapter, buffer);
|
||||||
|
|
||||||
|
|
||||||
if (avail == 0) {
|
if (avail == 0) {
|
||||||
rtpmp4venc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
rtpmp4venc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
}
|
}
|
||||||
gst_object_unref (rtpmp4venc);
|
|
||||||
|
|
||||||
ret = GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpmp4venc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpMP4VEnc *rtpmp4venc;
|
|
||||||
|
|
||||||
rtpmp4venc = GST_RTP_MP4V_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
rtpmp4venc->mtu = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
rtpmp4venc->pt = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
rtpmp4venc->ssrc = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpmp4venc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpMP4VEnc *rtpmp4venc;
|
|
||||||
|
|
||||||
rtpmp4venc = GST_RTP_MP4V_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
g_value_set_uint (value, rtpmp4venc->mtu);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
g_value_set_uint (value, rtpmp4venc->pt);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
g_value_set_uint (value, rtpmp4venc->ssrc);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_rtpmp4venc_change_state (GstElement * element, GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstRtpMP4VEnc *rtpmp4venc;
|
|
||||||
GstStateChangeReturn ret;
|
|
||||||
|
|
||||||
rtpmp4venc = GST_RTP_MP4V_ENC (element);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
||||||
rtpmp4venc->seqnum = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_rtpmp4venc_plugin_init (GstPlugin * plugin)
|
gst_rtpmp4venc_plugin_init (GstPlugin * plugin)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define __GST_RTP_MP4V_ENC_H__
|
#define __GST_RTP_MP4V_ENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/rtp/gstbasertppayload.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -41,26 +42,19 @@ typedef struct _GstRtpMP4VEncClass GstRtpMP4VEncClass;
|
||||||
|
|
||||||
struct _GstRtpMP4VEnc
|
struct _GstRtpMP4VEnc
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstBaseRTPPayload payload;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
GstAdapter *adapter;
|
GstAdapter *adapter;
|
||||||
GstClockTime first_ts;
|
GstClockTime first_ts;
|
||||||
guint16 seqnum;
|
|
||||||
|
|
||||||
gint rate;
|
gint rate;
|
||||||
gint profile;
|
gint profile;
|
||||||
|
GstBuffer *config;
|
||||||
guint mtu;
|
|
||||||
guint pt;
|
|
||||||
guint ssrc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstRtpMP4VEncClass
|
struct _GstRtpMP4VEncClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstBaseRTPPayloadClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
gboolean gst_rtpmp4venc_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtpmp4venc_plugin_init (GstPlugin * plugin);
|
||||||
|
|
|
@ -30,25 +30,6 @@ static GstElementDetails gst_rtp_mp4venc_details = {
|
||||||
"Wim Taymans <wim@fluendo.com>"
|
"Wim Taymans <wim@fluendo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RtpMP4VEnc signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DEFAULT_MTU 1024
|
|
||||||
#define DEFAULT_PT 96
|
|
||||||
#define DEFAULT_SSRC 0
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_MTU,
|
|
||||||
PROP_PT,
|
|
||||||
PROP_SSRC
|
|
||||||
};
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtpmp4venc_sink_template =
|
static GstStaticPadTemplate gst_rtpmp4venc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -61,9 +42,15 @@ static GstStaticPadTemplate gst_rtpmp4venc_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp,"
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
"rate=(int) [1, MAX]," "profile-level-id=[1,MAX]"
|
"media = (string) \"video\", "
|
||||||
/* "config=" */
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) [1, MAX ], "
|
||||||
|
"encoding_name = (string) \"MP4V-ES\", " "profile-level-id=[1,MAX]"
|
||||||
|
/* All optional parameters
|
||||||
|
*
|
||||||
|
* "config="
|
||||||
|
*/
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -71,19 +58,14 @@ GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
static void gst_rtpmp4venc_class_init (GstRtpMP4VEncClass * klass);
|
static void gst_rtpmp4venc_class_init (GstRtpMP4VEncClass * klass);
|
||||||
static void gst_rtpmp4venc_base_init (GstRtpMP4VEncClass * klass);
|
static void gst_rtpmp4venc_base_init (GstRtpMP4VEncClass * klass);
|
||||||
static void gst_rtpmp4venc_init (GstRtpMP4VEnc * rtpmp4venc);
|
static void gst_rtpmp4venc_init (GstRtpMP4VEnc * rtpmp4venc);
|
||||||
|
static void gst_rtpmp4venc_finalize (GObject * object);
|
||||||
|
|
||||||
static gboolean gst_rtpmp4venc_setcaps (GstPad * pad, GstCaps * caps);
|
static gboolean gst_rtpmp4venc_setcaps (GstBaseRTPPayload * payload,
|
||||||
static GstFlowReturn gst_rtpmp4venc_chain (GstPad * pad, GstBuffer * buffer);
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_rtpmp4venc_handle_buffer (GstBaseRTPPayload * payload,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
static void gst_rtpmp4venc_set_property (GObject * object, guint prop_id,
|
static GstBaseRTPPayloadClass *parent_class = NULL;
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_rtpmp4venc_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
|
|
||||||
static GstStateChangeReturn gst_rtpmp4venc_change_state (GstElement * element,
|
|
||||||
GstStateChange transition);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gst_rtpmp4venc_get_type (void)
|
gst_rtpmp4venc_get_type (void)
|
||||||
|
@ -104,7 +86,7 @@ gst_rtpmp4venc_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
rtpmp4venc_type =
|
rtpmp4venc_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRtpMP4VEnc",
|
g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpMP4VEnc",
|
||||||
&rtpmp4venc_info, 0);
|
&rtpmp4venc_info, 0);
|
||||||
}
|
}
|
||||||
return rtpmp4venc_type;
|
return rtpmp4venc_type;
|
||||||
|
@ -128,69 +110,58 @@ gst_rtpmp4venc_class_init (GstRtpMP4VEncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtpmp4venc_set_property;
|
gobject_class->finalize = gst_rtpmp4venc_finalize;
|
||||||
gobject_class->get_property = gst_rtpmp4venc_get_property;
|
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
|
gstbasertppayload_class->set_caps = gst_rtpmp4venc_setcaps;
|
||||||
g_param_spec_uint ("mtu", "MTU",
|
gstbasertppayload_class->handle_buffer = gst_rtpmp4venc_handle_buffer;
|
||||||
"Maximum size of one packet",
|
|
||||||
28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
|
|
||||||
g_param_spec_uint ("pt", "payload type",
|
|
||||||
"The payload type of the packets",
|
|
||||||
0, 0x80, DEFAULT_PT, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
|
|
||||||
g_param_spec_uint ("ssrc", "SSRC",
|
|
||||||
"The SSRC of the packets",
|
|
||||||
0, G_MAXUINT, DEFAULT_SSRC, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtpmp4venc_change_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtpmp4venc_init (GstRtpMP4VEnc * rtpmp4venc)
|
gst_rtpmp4venc_init (GstRtpMP4VEnc * rtpmp4venc)
|
||||||
{
|
{
|
||||||
rtpmp4venc->srcpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpmp4venc_src_template), "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpmp4venc), rtpmp4venc->srcpad);
|
|
||||||
|
|
||||||
rtpmp4venc->sinkpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpmp4venc_sink_template), "sink");
|
|
||||||
gst_pad_set_setcaps_function (rtpmp4venc->sinkpad, gst_rtpmp4venc_setcaps);
|
|
||||||
gst_pad_set_chain_function (rtpmp4venc->sinkpad, gst_rtpmp4venc_chain);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpmp4venc), rtpmp4venc->sinkpad);
|
|
||||||
|
|
||||||
rtpmp4venc->adapter = gst_adapter_new ();
|
rtpmp4venc->adapter = gst_adapter_new ();
|
||||||
rtpmp4venc->mtu = DEFAULT_MTU;
|
|
||||||
rtpmp4venc->pt = DEFAULT_PT;
|
|
||||||
rtpmp4venc->ssrc = DEFAULT_SSRC;
|
|
||||||
rtpmp4venc->rate = 90000;
|
rtpmp4venc->rate = 90000;
|
||||||
rtpmp4venc->profile = 1;
|
rtpmp4venc->profile = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_rtpmp4venc_setcaps (GstPad * pad, GstCaps * caps)
|
gst_rtpmp4venc_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstRtpMP4VEnc *rtpmp4venc;
|
GstRtpMP4VEnc *rtpmp4venc;
|
||||||
GstCaps *srccaps;
|
|
||||||
|
|
||||||
rtpmp4venc = GST_RTP_MP4V_ENC (gst_pad_get_parent (pad));
|
rtpmp4venc = GST_RTP_MP4V_ENC (object);
|
||||||
|
|
||||||
srccaps = gst_caps_new_simple ("application/x-rtp",
|
g_object_unref (rtpmp4venc->adapter);
|
||||||
"rate", G_TYPE_INT, rtpmp4venc->rate,
|
rtpmp4venc->adapter = NULL;
|
||||||
"profile-level-id", G_TYPE_INT, rtpmp4venc->profile, NULL);
|
|
||||||
gst_pad_set_caps (rtpmp4venc->srcpad, srccaps);
|
|
||||||
gst_caps_unref (srccaps);
|
|
||||||
|
|
||||||
gst_object_unref (rtpmp4venc);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtpmp4venc_new_caps (GstRtpMP4VEnc * rtpmp4venc)
|
||||||
|
{
|
||||||
|
gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4venc),
|
||||||
|
"profile-level-id", G_TYPE_INT, rtpmp4venc->profile,
|
||||||
|
"config", GST_TYPE_BUFFER, rtpmp4venc->config, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtpmp4venc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
|
||||||
|
{
|
||||||
|
GstRtpMP4VEnc *rtpmp4venc;
|
||||||
|
|
||||||
|
rtpmp4venc = GST_RTP_MP4V_ENC (payload);
|
||||||
|
|
||||||
|
gst_basertppayload_set_options (payload, "video", TRUE, "MP4V-ES",
|
||||||
|
rtpmp4venc->rate);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -201,7 +172,6 @@ gst_rtpmp4venc_flush (GstRtpMP4VEnc * rtpmp4venc)
|
||||||
guint avail;
|
guint avail;
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
guint16 frag_offset;
|
|
||||||
|
|
||||||
/* the data available in the adapter is either smaller
|
/* the data available in the adapter is either smaller
|
||||||
* than the MTU or bigger. In the case it is smaller, the complete
|
* than the MTU or bigger. In the case it is smaller, the complete
|
||||||
|
@ -212,7 +182,6 @@ gst_rtpmp4venc_flush (GstRtpMP4VEnc * rtpmp4venc)
|
||||||
|
|
||||||
ret = GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
|
|
||||||
frag_offset = 0;
|
|
||||||
while (avail > 0) {
|
while (avail > 0) {
|
||||||
guint towrite;
|
guint towrite;
|
||||||
guint8 *payload;
|
guint8 *payload;
|
||||||
|
@ -224,159 +193,149 @@ gst_rtpmp4venc_flush (GstRtpMP4VEnc * rtpmp4venc)
|
||||||
packet_len = gst_rtpbuffer_calc_packet_len (avail, 0, 0);
|
packet_len = gst_rtpbuffer_calc_packet_len (avail, 0, 0);
|
||||||
|
|
||||||
/* fill one MTU or all available bytes */
|
/* fill one MTU or all available bytes */
|
||||||
towrite = MIN (packet_len, rtpmp4venc->mtu);
|
towrite = MIN (packet_len, GST_BASE_RTP_PAYLOAD_MTU (rtpmp4venc));
|
||||||
|
|
||||||
/* this is the payload length */
|
/* this is the payload length */
|
||||||
payload_len = gst_rtpbuffer_calc_payload_len (towrite, 0, 0);
|
payload_len = gst_rtpbuffer_calc_payload_len (towrite, 0, 0);
|
||||||
|
|
||||||
/* create buffer to hold the payload */
|
/* create buffer to hold the payload */
|
||||||
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
|
||||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpmp4venc->srcpad));
|
|
||||||
|
|
||||||
/* set timestamp */
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (rtpmp4venc->first_ts)) {
|
|
||||||
gst_rtpbuffer_set_timestamp (outbuf,
|
|
||||||
rtpmp4venc->first_ts * 90000 / GST_SECOND);
|
|
||||||
}
|
|
||||||
gst_rtpbuffer_set_payload_type (outbuf, rtpmp4venc->pt);
|
|
||||||
gst_rtpbuffer_set_seq (outbuf, rtpmp4venc->seqnum++);
|
|
||||||
|
|
||||||
|
/* copy payload */
|
||||||
payload = gst_rtpbuffer_get_payload (outbuf);
|
payload = gst_rtpbuffer_get_payload (outbuf);
|
||||||
|
|
||||||
data = (guint8 *) gst_adapter_peek (rtpmp4venc->adapter, payload_len);
|
data = (guint8 *) gst_adapter_peek (rtpmp4venc->adapter, payload_len);
|
||||||
memcpy (payload, data, payload_len);
|
memcpy (payload, data, payload_len);
|
||||||
|
|
||||||
gst_adapter_flush (rtpmp4venc->adapter, payload_len);
|
gst_adapter_flush (rtpmp4venc->adapter, payload_len);
|
||||||
|
|
||||||
avail -= payload_len;
|
avail -= payload_len;
|
||||||
frag_offset += payload_len;
|
|
||||||
|
|
||||||
gst_rtpbuffer_set_marker (outbuf, avail == 0);
|
gst_rtpbuffer_set_marker (outbuf, avail == 0);
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4venc->first_ts;
|
GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4venc->first_ts;
|
||||||
|
|
||||||
ret = gst_pad_push (rtpmp4venc->srcpad, outbuf);
|
ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmp4venc), outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define VOS_STARTCODE 0x000001B0
|
||||||
|
#define VOS_ENDCODE 0x000001B1
|
||||||
|
#define USER_DATA_STARTCODE 0x000001B2
|
||||||
|
#define GOP_STARTCODE 0x000001B3
|
||||||
|
#define VISUAL_OBJECT_STARTCODE 0x000001B5
|
||||||
|
#define VOP_STARTCODE 0x000001B6
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtpmp4venc_parse_data (GstRtpMP4VEnc * enc, guint8 * data, guint size)
|
||||||
|
{
|
||||||
|
guint32 code;
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
|
if (size < 5)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
code = GST_READ_UINT32_BE (data);
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case VOS_STARTCODE:
|
||||||
|
{
|
||||||
|
gint i;
|
||||||
|
guint8 profile;
|
||||||
|
gboolean newprofile = FALSE;
|
||||||
|
gboolean equal;
|
||||||
|
|
||||||
|
/* profile_and_level_indication */
|
||||||
|
profile = data[4];
|
||||||
|
|
||||||
|
if (profile != enc->profile) {
|
||||||
|
newprofile = TRUE;
|
||||||
|
enc->profile = profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* up to the next GOP_STARTCODE or VOP_STARTCODE is
|
||||||
|
* the config information */
|
||||||
|
code = 0xffffffff;
|
||||||
|
for (i = 5; i < size - 4; i++) {
|
||||||
|
code = (code << 8) | data[i];
|
||||||
|
if (code == GOP_STARTCODE || code == VOP_STARTCODE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i -= 3;
|
||||||
|
/* see if config changed */
|
||||||
|
equal = FALSE;
|
||||||
|
if (enc->config) {
|
||||||
|
if (GST_BUFFER_SIZE (enc->config) == i) {
|
||||||
|
equal = memcmp (GST_BUFFER_DATA (enc->config), data, i) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if config string changed or new profile, make new caps */
|
||||||
|
if (!equal || newprofile) {
|
||||||
|
if (enc->config)
|
||||||
|
gst_buffer_unref (enc->config);
|
||||||
|
enc->config = gst_buffer_new_and_alloc (i);
|
||||||
|
memcpy (GST_BUFFER_DATA (enc->config), data, i);
|
||||||
|
gst_rtpmp4venc_new_caps (enc);
|
||||||
|
}
|
||||||
|
result = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VOP_STARTCODE:
|
||||||
|
result = FALSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* we expect buffers starting on startcodes.
|
/* we expect buffers starting on startcodes.
|
||||||
*
|
|
||||||
* FIXME, need to flush the adapter if we receive non VOP
|
|
||||||
* packets.
|
|
||||||
*/
|
*/
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtpmp4venc_chain (GstPad * pad, GstBuffer * buffer)
|
gst_rtpmp4venc_handle_buffer (GstBaseRTPPayload * basepayload,
|
||||||
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstRtpMP4VEnc *rtpmp4venc;
|
GstRtpMP4VEnc *rtpmp4venc;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
guint size, avail;
|
guint size, avail;
|
||||||
guint packet_len;
|
guint packet_len;
|
||||||
|
guint8 *data;
|
||||||
|
gboolean flush;
|
||||||
|
|
||||||
rtpmp4venc = GST_RTP_MP4V_ENC (gst_pad_get_parent (pad));
|
rtpmp4venc = GST_RTP_MP4V_ENC (basepayload);
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (buffer);
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
|
data = GST_BUFFER_DATA (buffer);
|
||||||
avail = gst_adapter_available (rtpmp4venc->adapter);
|
avail = gst_adapter_available (rtpmp4venc->adapter);
|
||||||
|
|
||||||
|
/* parse incomming data and see if we need to start a new RTP
|
||||||
|
* packet */
|
||||||
|
flush = gst_rtpmp4venc_parse_data (rtpmp4venc, data, size);
|
||||||
|
|
||||||
/* get packet length of previous data and this new data */
|
/* get packet length of previous data and this new data */
|
||||||
packet_len = gst_rtpbuffer_calc_packet_len (avail + size, 0, 0);
|
packet_len = gst_rtpbuffer_calc_packet_len (avail + size, 0, 0);
|
||||||
|
|
||||||
/* if this buffer is going to overflow the packet, flush what we
|
/* if this buffer is going to overflow the packet, flush what we
|
||||||
* have. */
|
* have. */
|
||||||
if (packet_len > rtpmp4venc->mtu) {
|
if (flush || packet_len > GST_BASE_RTP_PAYLOAD_MTU (rtpmp4venc)) {
|
||||||
ret = gst_rtpmp4venc_flush (rtpmp4venc);
|
ret = gst_rtpmp4venc_flush (rtpmp4venc);
|
||||||
avail = 0;
|
avail = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_adapter_push (rtpmp4venc->adapter, buffer);
|
gst_adapter_push (rtpmp4venc->adapter, buffer);
|
||||||
|
|
||||||
|
|
||||||
if (avail == 0) {
|
if (avail == 0) {
|
||||||
rtpmp4venc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
rtpmp4venc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
}
|
}
|
||||||
gst_object_unref (rtpmp4venc);
|
|
||||||
|
|
||||||
ret = GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpmp4venc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpMP4VEnc *rtpmp4venc;
|
|
||||||
|
|
||||||
rtpmp4venc = GST_RTP_MP4V_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
rtpmp4venc->mtu = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
rtpmp4venc->pt = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
rtpmp4venc->ssrc = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpmp4venc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpMP4VEnc *rtpmp4venc;
|
|
||||||
|
|
||||||
rtpmp4venc = GST_RTP_MP4V_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
g_value_set_uint (value, rtpmp4venc->mtu);
|
|
||||||
break;
|
|
||||||
case PROP_PT:
|
|
||||||
g_value_set_uint (value, rtpmp4venc->pt);
|
|
||||||
break;
|
|
||||||
case PROP_SSRC:
|
|
||||||
g_value_set_uint (value, rtpmp4venc->ssrc);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_rtpmp4venc_change_state (GstElement * element, GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstRtpMP4VEnc *rtpmp4venc;
|
|
||||||
GstStateChangeReturn ret;
|
|
||||||
|
|
||||||
rtpmp4venc = GST_RTP_MP4V_ENC (element);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
||||||
rtpmp4venc->seqnum = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_rtpmp4venc_plugin_init (GstPlugin * plugin)
|
gst_rtpmp4venc_plugin_init (GstPlugin * plugin)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define __GST_RTP_MP4V_ENC_H__
|
#define __GST_RTP_MP4V_ENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/rtp/gstbasertppayload.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -41,26 +42,19 @@ typedef struct _GstRtpMP4VEncClass GstRtpMP4VEncClass;
|
||||||
|
|
||||||
struct _GstRtpMP4VEnc
|
struct _GstRtpMP4VEnc
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstBaseRTPPayload payload;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
GstAdapter *adapter;
|
GstAdapter *adapter;
|
||||||
GstClockTime first_ts;
|
GstClockTime first_ts;
|
||||||
guint16 seqnum;
|
|
||||||
|
|
||||||
gint rate;
|
gint rate;
|
||||||
gint profile;
|
gint profile;
|
||||||
|
GstBuffer *config;
|
||||||
guint mtu;
|
|
||||||
guint pt;
|
|
||||||
guint ssrc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstRtpMP4VEncClass
|
struct _GstRtpMP4VEncClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstBaseRTPPayloadClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
gboolean gst_rtpmp4venc_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtpmp4venc_plugin_init (GstPlugin * plugin);
|
||||||
|
|
|
@ -53,7 +53,10 @@ static GstStaticPadTemplate gst_rtpmpadec_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp")
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"audio\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 90000, " "encoding_name = (string) \"MPA\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,10 @@ static GstStaticPadTemplate gst_rtpmpadec_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp")
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"audio\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 90000, " "encoding_name = (string) \"MPA\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,21 +30,6 @@ static GstElementDetails gst_rtp_mpaenc_details = {
|
||||||
"Wim Taymans <wim@fluendo.com>"
|
"Wim Taymans <wim@fluendo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RtpMPAEnc signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DEFAULT_MTU 1024
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_MTU
|
|
||||||
};
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtpmpaenc_sink_template =
|
static GstStaticPadTemplate gst_rtpmpaenc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -56,25 +41,23 @@ static GstStaticPadTemplate gst_rtpmpaenc_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp")
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"audio\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 90000, " "encoding_name = (string) \"MPA\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void gst_rtpmpaenc_class_init (GstRtpMPAEncClass * klass);
|
static void gst_rtpmpaenc_class_init (GstRtpMPAEncClass * klass);
|
||||||
static void gst_rtpmpaenc_base_init (GstRtpMPAEncClass * klass);
|
static void gst_rtpmpaenc_base_init (GstRtpMPAEncClass * klass);
|
||||||
static void gst_rtpmpaenc_init (GstRtpMPAEnc * rtpmpaenc);
|
static void gst_rtpmpaenc_init (GstRtpMPAEnc * rtpmpaenc);
|
||||||
|
static void gst_rtpmpaenc_finalize (GObject * object);
|
||||||
|
|
||||||
static GstFlowReturn gst_rtpmpaenc_chain (GstPad * pad, GstBuffer * buffer);
|
static gboolean gst_rtpmpaenc_setcaps (GstBaseRTPPayload * payload,
|
||||||
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_rtpmpaenc_handle_buffer (GstBaseRTPPayload * payload,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
static void gst_rtpmpaenc_set_property (GObject * object, guint prop_id,
|
static GstBaseRTPPayloadClass *parent_class = NULL;
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_rtpmpaenc_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
|
|
||||||
static GstStateChangeReturn gst_rtpmpaenc_change_state (GstElement * element,
|
|
||||||
GstStateChange transition);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gst_rtpmpaenc_get_type (void)
|
gst_rtpmpaenc_get_type (void)
|
||||||
|
@ -95,7 +78,7 @@ gst_rtpmpaenc_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
rtpmpaenc_type =
|
rtpmpaenc_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRtpMPAEnc",
|
g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpMPAEnc",
|
||||||
&rtpmpaenc_info, 0);
|
&rtpmpaenc_info, 0);
|
||||||
}
|
}
|
||||||
return rtpmpaenc_type;
|
return rtpmpaenc_type;
|
||||||
|
@ -119,39 +102,46 @@ gst_rtpmpaenc_class_init (GstRtpMPAEncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtpmpaenc_set_property;
|
gobject_class->finalize = gst_rtpmpaenc_finalize;
|
||||||
gobject_class->get_property = gst_rtpmpaenc_get_property;
|
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
|
gstbasertppayload_class->set_caps = gst_rtpmpaenc_setcaps;
|
||||||
g_param_spec_uint ("mtu", "MTU",
|
gstbasertppayload_class->handle_buffer = gst_rtpmpaenc_handle_buffer;
|
||||||
"Maximum size of one packet",
|
|
||||||
28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtpmpaenc_change_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtpmpaenc_init (GstRtpMPAEnc * rtpmpaenc)
|
gst_rtpmpaenc_init (GstRtpMPAEnc * rtpmpaenc)
|
||||||
{
|
{
|
||||||
rtpmpaenc->srcpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpmpaenc_src_template), "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpmpaenc), rtpmpaenc->srcpad);
|
|
||||||
|
|
||||||
rtpmpaenc->sinkpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpmpaenc_sink_template), "sink");
|
|
||||||
gst_pad_set_chain_function (rtpmpaenc->sinkpad, gst_rtpmpaenc_chain);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpmpaenc), rtpmpaenc->sinkpad);
|
|
||||||
|
|
||||||
rtpmpaenc->adapter = gst_adapter_new ();
|
rtpmpaenc->adapter = gst_adapter_new ();
|
||||||
rtpmpaenc->mtu = DEFAULT_MTU;
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtpmpaenc_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
GstRtpMPAEnc *rtpmpaenc;
|
||||||
|
|
||||||
|
rtpmpaenc = GST_RTP_MPA_ENC (object);
|
||||||
|
|
||||||
|
g_object_unref (rtpmpaenc->adapter);
|
||||||
|
rtpmpaenc->adapter = NULL;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtpmpaenc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
|
||||||
|
{
|
||||||
|
gst_basertppayload_set_options (payload, "audio", TRUE, "MPA", 90000);
|
||||||
|
gst_basertppayload_set_outcaps (payload, NULL);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -184,7 +174,7 @@ gst_rtpmpaenc_flush (GstRtpMPAEnc * rtpmpaenc)
|
||||||
packet_len = gst_rtpbuffer_calc_packet_len (4 + avail, 0, 0);
|
packet_len = gst_rtpbuffer_calc_packet_len (4 + avail, 0, 0);
|
||||||
|
|
||||||
/* fill one MTU or all available bytes */
|
/* fill one MTU or all available bytes */
|
||||||
towrite = MIN (packet_len, rtpmpaenc->mtu);
|
towrite = MIN (packet_len, GST_BASE_RTP_PAYLOAD_MTU (rtpmpaenc));
|
||||||
|
|
||||||
/* this is the payload length */
|
/* this is the payload length */
|
||||||
payload_len = gst_rtpbuffer_calc_payload_len (towrite, 0, 0);
|
payload_len = gst_rtpbuffer_calc_payload_len (towrite, 0, 0);
|
||||||
|
@ -194,11 +184,7 @@ gst_rtpmpaenc_flush (GstRtpMPAEnc * rtpmpaenc)
|
||||||
|
|
||||||
payload_len -= 4;
|
payload_len -= 4;
|
||||||
|
|
||||||
/* set timestamp */
|
|
||||||
gst_rtpbuffer_set_timestamp (outbuf,
|
|
||||||
rtpmpaenc->first_ts * 90000 / GST_SECOND);
|
|
||||||
gst_rtpbuffer_set_payload_type (outbuf, GST_RTP_PAYLOAD_MPA);
|
gst_rtpbuffer_set_payload_type (outbuf, GST_RTP_PAYLOAD_MPA);
|
||||||
gst_rtpbuffer_set_seq (outbuf, rtpmpaenc->seqnum++);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 0 1 2 3
|
* 0 1 2 3
|
||||||
|
@ -225,21 +211,22 @@ gst_rtpmpaenc_flush (GstRtpMPAEnc * rtpmpaenc)
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = rtpmpaenc->first_ts;
|
GST_BUFFER_TIMESTAMP (outbuf) = rtpmpaenc->first_ts;
|
||||||
|
|
||||||
ret = gst_pad_push (rtpmpaenc->srcpad, outbuf);
|
ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmpaenc), outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtpmpaenc_chain (GstPad * pad, GstBuffer * buffer)
|
gst_rtpmpaenc_handle_buffer (GstBaseRTPPayload * basepayload,
|
||||||
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstRtpMPAEnc *rtpmpaenc;
|
GstRtpMPAEnc *rtpmpaenc;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
guint size, avail;
|
guint size, avail;
|
||||||
guint packet_len;
|
guint packet_len;
|
||||||
|
|
||||||
rtpmpaenc = GST_RTP_MPA_ENC (gst_pad_get_parent (pad));
|
rtpmpaenc = GST_RTP_MPA_ENC (basepayload);
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (buffer);
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
avail = gst_adapter_available (rtpmpaenc->adapter);
|
avail = gst_adapter_available (rtpmpaenc->adapter);
|
||||||
|
@ -250,9 +237,11 @@ gst_rtpmpaenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
/* if this buffer is going to overflow the packet, flush what we
|
/* if this buffer is going to overflow the packet, flush what we
|
||||||
* have. */
|
* have. */
|
||||||
if (packet_len > rtpmpaenc->mtu) {
|
if (packet_len > GST_BASE_RTP_PAYLOAD_MTU (rtpmpaenc)) {
|
||||||
ret = gst_rtpmpaenc_flush (rtpmpaenc);
|
ret = gst_rtpmpaenc_flush (rtpmpaenc);
|
||||||
avail = 0;
|
avail = 0;
|
||||||
|
} else {
|
||||||
|
ret = GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_adapter_push (rtpmpaenc->adapter, buffer);
|
gst_adapter_push (rtpmpaenc->adapter, buffer);
|
||||||
|
@ -260,75 +249,7 @@ gst_rtpmpaenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
if (avail == 0) {
|
if (avail == 0) {
|
||||||
rtpmpaenc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
rtpmpaenc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
}
|
}
|
||||||
gst_object_unref (rtpmpaenc);
|
|
||||||
|
|
||||||
ret = GST_FLOW_OK;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpmpaenc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpMPAEnc *rtpmpaenc;
|
|
||||||
|
|
||||||
rtpmpaenc = GST_RTP_MPA_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
rtpmpaenc->mtu = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpmpaenc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpMPAEnc *rtpmpaenc;
|
|
||||||
|
|
||||||
rtpmpaenc = GST_RTP_MPA_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
g_value_set_uint (value, rtpmpaenc->mtu);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_rtpmpaenc_change_state (GstElement * element, GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstRtpMPAEnc *rtpmpaenc;
|
|
||||||
GstStateChangeReturn ret;
|
|
||||||
|
|
||||||
rtpmpaenc = GST_RTP_MPA_ENC (element);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
||||||
rtpmpaenc->seqnum = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define __GST_RTP_MPA_ENC_H__
|
#define __GST_RTP_MPA_ENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/rtp/gstbasertppayload.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -41,21 +42,15 @@ typedef struct _GstRtpMPAEncClass GstRtpMPAEncClass;
|
||||||
|
|
||||||
struct _GstRtpMPAEnc
|
struct _GstRtpMPAEnc
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstBaseRTPPayload payload;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
GstAdapter *adapter;
|
GstAdapter *adapter;
|
||||||
GstClockTime first_ts;
|
GstClockTime first_ts;
|
||||||
guint16 seqnum;
|
|
||||||
|
|
||||||
guint mtu;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstRtpMPAEncClass
|
struct _GstRtpMPAEncClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstBaseRTPPayloadClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
gboolean gst_rtpmpaenc_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtpmpaenc_plugin_init (GstPlugin * plugin);
|
||||||
|
|
|
@ -30,21 +30,6 @@ static GstElementDetails gst_rtp_mpaenc_details = {
|
||||||
"Wim Taymans <wim@fluendo.com>"
|
"Wim Taymans <wim@fluendo.com>"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RtpMPAEnc signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* FILL ME */
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DEFAULT_MTU 1024
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_MTU
|
|
||||||
};
|
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtpmpaenc_sink_template =
|
static GstStaticPadTemplate gst_rtpmpaenc_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -56,25 +41,23 @@ static GstStaticPadTemplate gst_rtpmpaenc_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("application/x-rtp")
|
GST_STATIC_CAPS ("application/x-rtp, "
|
||||||
|
"media = (string) \"audio\", "
|
||||||
|
"payload = (int) [ 96, 255 ], "
|
||||||
|
"clock_rate = (int) 90000, " "encoding_name = (string) \"MPA\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void gst_rtpmpaenc_class_init (GstRtpMPAEncClass * klass);
|
static void gst_rtpmpaenc_class_init (GstRtpMPAEncClass * klass);
|
||||||
static void gst_rtpmpaenc_base_init (GstRtpMPAEncClass * klass);
|
static void gst_rtpmpaenc_base_init (GstRtpMPAEncClass * klass);
|
||||||
static void gst_rtpmpaenc_init (GstRtpMPAEnc * rtpmpaenc);
|
static void gst_rtpmpaenc_init (GstRtpMPAEnc * rtpmpaenc);
|
||||||
|
static void gst_rtpmpaenc_finalize (GObject * object);
|
||||||
|
|
||||||
static GstFlowReturn gst_rtpmpaenc_chain (GstPad * pad, GstBuffer * buffer);
|
static gboolean gst_rtpmpaenc_setcaps (GstBaseRTPPayload * payload,
|
||||||
|
GstCaps * caps);
|
||||||
|
static GstFlowReturn gst_rtpmpaenc_handle_buffer (GstBaseRTPPayload * payload,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
static void gst_rtpmpaenc_set_property (GObject * object, guint prop_id,
|
static GstBaseRTPPayloadClass *parent_class = NULL;
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_rtpmpaenc_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
|
|
||||||
static GstStateChangeReturn gst_rtpmpaenc_change_state (GstElement * element,
|
|
||||||
GstStateChange transition);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gst_rtpmpaenc_get_type (void)
|
gst_rtpmpaenc_get_type (void)
|
||||||
|
@ -95,7 +78,7 @@ gst_rtpmpaenc_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
rtpmpaenc_type =
|
rtpmpaenc_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRtpMPAEnc",
|
g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpMPAEnc",
|
||||||
&rtpmpaenc_info, 0);
|
&rtpmpaenc_info, 0);
|
||||||
}
|
}
|
||||||
return rtpmpaenc_type;
|
return rtpmpaenc_type;
|
||||||
|
@ -119,39 +102,46 @@ gst_rtpmpaenc_class_init (GstRtpMPAEncClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *gstelement_class;
|
GstElementClass *gstelement_class;
|
||||||
|
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
gobject_class->set_property = gst_rtpmpaenc_set_property;
|
gobject_class->finalize = gst_rtpmpaenc_finalize;
|
||||||
gobject_class->get_property = gst_rtpmpaenc_get_property;
|
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
|
gstbasertppayload_class->set_caps = gst_rtpmpaenc_setcaps;
|
||||||
g_param_spec_uint ("mtu", "MTU",
|
gstbasertppayload_class->handle_buffer = gst_rtpmpaenc_handle_buffer;
|
||||||
"Maximum size of one packet",
|
|
||||||
28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE));
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_rtpmpaenc_change_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtpmpaenc_init (GstRtpMPAEnc * rtpmpaenc)
|
gst_rtpmpaenc_init (GstRtpMPAEnc * rtpmpaenc)
|
||||||
{
|
{
|
||||||
rtpmpaenc->srcpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpmpaenc_src_template), "src");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpmpaenc), rtpmpaenc->srcpad);
|
|
||||||
|
|
||||||
rtpmpaenc->sinkpad =
|
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
|
||||||
(&gst_rtpmpaenc_sink_template), "sink");
|
|
||||||
gst_pad_set_chain_function (rtpmpaenc->sinkpad, gst_rtpmpaenc_chain);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (rtpmpaenc), rtpmpaenc->sinkpad);
|
|
||||||
|
|
||||||
rtpmpaenc->adapter = gst_adapter_new ();
|
rtpmpaenc->adapter = gst_adapter_new ();
|
||||||
rtpmpaenc->mtu = DEFAULT_MTU;
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtpmpaenc_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
GstRtpMPAEnc *rtpmpaenc;
|
||||||
|
|
||||||
|
rtpmpaenc = GST_RTP_MPA_ENC (object);
|
||||||
|
|
||||||
|
g_object_unref (rtpmpaenc->adapter);
|
||||||
|
rtpmpaenc->adapter = NULL;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtpmpaenc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
|
||||||
|
{
|
||||||
|
gst_basertppayload_set_options (payload, "audio", TRUE, "MPA", 90000);
|
||||||
|
gst_basertppayload_set_outcaps (payload, NULL);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -184,7 +174,7 @@ gst_rtpmpaenc_flush (GstRtpMPAEnc * rtpmpaenc)
|
||||||
packet_len = gst_rtpbuffer_calc_packet_len (4 + avail, 0, 0);
|
packet_len = gst_rtpbuffer_calc_packet_len (4 + avail, 0, 0);
|
||||||
|
|
||||||
/* fill one MTU or all available bytes */
|
/* fill one MTU or all available bytes */
|
||||||
towrite = MIN (packet_len, rtpmpaenc->mtu);
|
towrite = MIN (packet_len, GST_BASE_RTP_PAYLOAD_MTU (rtpmpaenc));
|
||||||
|
|
||||||
/* this is the payload length */
|
/* this is the payload length */
|
||||||
payload_len = gst_rtpbuffer_calc_payload_len (towrite, 0, 0);
|
payload_len = gst_rtpbuffer_calc_payload_len (towrite, 0, 0);
|
||||||
|
@ -194,11 +184,7 @@ gst_rtpmpaenc_flush (GstRtpMPAEnc * rtpmpaenc)
|
||||||
|
|
||||||
payload_len -= 4;
|
payload_len -= 4;
|
||||||
|
|
||||||
/* set timestamp */
|
|
||||||
gst_rtpbuffer_set_timestamp (outbuf,
|
|
||||||
rtpmpaenc->first_ts * 90000 / GST_SECOND);
|
|
||||||
gst_rtpbuffer_set_payload_type (outbuf, GST_RTP_PAYLOAD_MPA);
|
gst_rtpbuffer_set_payload_type (outbuf, GST_RTP_PAYLOAD_MPA);
|
||||||
gst_rtpbuffer_set_seq (outbuf, rtpmpaenc->seqnum++);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 0 1 2 3
|
* 0 1 2 3
|
||||||
|
@ -225,21 +211,22 @@ gst_rtpmpaenc_flush (GstRtpMPAEnc * rtpmpaenc)
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = rtpmpaenc->first_ts;
|
GST_BUFFER_TIMESTAMP (outbuf) = rtpmpaenc->first_ts;
|
||||||
|
|
||||||
ret = gst_pad_push (rtpmpaenc->srcpad, outbuf);
|
ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmpaenc), outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtpmpaenc_chain (GstPad * pad, GstBuffer * buffer)
|
gst_rtpmpaenc_handle_buffer (GstBaseRTPPayload * basepayload,
|
||||||
|
GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstRtpMPAEnc *rtpmpaenc;
|
GstRtpMPAEnc *rtpmpaenc;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
guint size, avail;
|
guint size, avail;
|
||||||
guint packet_len;
|
guint packet_len;
|
||||||
|
|
||||||
rtpmpaenc = GST_RTP_MPA_ENC (gst_pad_get_parent (pad));
|
rtpmpaenc = GST_RTP_MPA_ENC (basepayload);
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (buffer);
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
avail = gst_adapter_available (rtpmpaenc->adapter);
|
avail = gst_adapter_available (rtpmpaenc->adapter);
|
||||||
|
@ -250,9 +237,11 @@ gst_rtpmpaenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
/* if this buffer is going to overflow the packet, flush what we
|
/* if this buffer is going to overflow the packet, flush what we
|
||||||
* have. */
|
* have. */
|
||||||
if (packet_len > rtpmpaenc->mtu) {
|
if (packet_len > GST_BASE_RTP_PAYLOAD_MTU (rtpmpaenc)) {
|
||||||
ret = gst_rtpmpaenc_flush (rtpmpaenc);
|
ret = gst_rtpmpaenc_flush (rtpmpaenc);
|
||||||
avail = 0;
|
avail = 0;
|
||||||
|
} else {
|
||||||
|
ret = GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_adapter_push (rtpmpaenc->adapter, buffer);
|
gst_adapter_push (rtpmpaenc->adapter, buffer);
|
||||||
|
@ -260,75 +249,7 @@ gst_rtpmpaenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
if (avail == 0) {
|
if (avail == 0) {
|
||||||
rtpmpaenc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
rtpmpaenc->first_ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
}
|
}
|
||||||
gst_object_unref (rtpmpaenc);
|
|
||||||
|
|
||||||
ret = GST_FLOW_OK;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpmpaenc_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpMPAEnc *rtpmpaenc;
|
|
||||||
|
|
||||||
rtpmpaenc = GST_RTP_MPA_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
rtpmpaenc->mtu = g_value_get_uint (value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_rtpmpaenc_get_property (GObject * object, guint prop_id, GValue * value,
|
|
||||||
GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
GstRtpMPAEnc *rtpmpaenc;
|
|
||||||
|
|
||||||
rtpmpaenc = GST_RTP_MPA_ENC (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case PROP_MTU:
|
|
||||||
g_value_set_uint (value, rtpmpaenc->mtu);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_rtpmpaenc_change_state (GstElement * element, GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstRtpMPAEnc *rtpmpaenc;
|
|
||||||
GstStateChangeReturn ret;
|
|
||||||
|
|
||||||
rtpmpaenc = GST_RTP_MPA_ENC (element);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
||||||
rtpmpaenc->seqnum = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define __GST_RTP_MPA_ENC_H__
|
#define __GST_RTP_MPA_ENC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/rtp/gstbasertppayload.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -41,21 +42,15 @@ typedef struct _GstRtpMPAEncClass GstRtpMPAEncClass;
|
||||||
|
|
||||||
struct _GstRtpMPAEnc
|
struct _GstRtpMPAEnc
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstBaseRTPPayload payload;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
|
||||||
GstPad *srcpad;
|
|
||||||
|
|
||||||
GstAdapter *adapter;
|
GstAdapter *adapter;
|
||||||
GstClockTime first_ts;
|
GstClockTime first_ts;
|
||||||
guint16 seqnum;
|
|
||||||
|
|
||||||
guint mtu;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstRtpMPAEncClass
|
struct _GstRtpMPAEncClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstBaseRTPPayloadClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
gboolean gst_rtpmpaenc_plugin_init (GstPlugin * plugin);
|
gboolean gst_rtpmpaenc_plugin_init (GstPlugin * plugin);
|
||||||
|
|
Loading…
Reference in a new issue