rtpvp8: Add simple payloaders and depayloaders for VP8

Minimal implementation of http://www.webmproject.org/code/specs/rtp/,
version 0.3.2
This commit is contained in:
Sjoerd Simons 2010-05-16 17:23:17 +01:00 committed by Tim-Philipp Müller
parent d6fd0ebd04
commit e9f4e9342f
6 changed files with 844 additions and 0 deletions

29
gst/rtp/dboolhuff.LICENSE Normal file
View file

@ -0,0 +1,29 @@
Copyright (c) 2010, Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Google nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

21
gst/rtp/gstrtpvp8.c Normal file
View file

@ -0,0 +1,21 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstrtpvp8pay.h"
#include "gstrtpvp8depay.h"
static gboolean
plugin_init (GstPlugin *plugin)
{
gst_rtp_vp8_depay_plugin_init (plugin);
gst_rtp_vp8_pay_plugin_init (plugin);
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"rtpvp8",
"rtpvp8",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

193
gst/rtp/gstrtpvp8depay.c Normal file
View file

@ -0,0 +1,193 @@
/*
* gst-rtp-vp8-depay.c - Source for GstRtpVP8Depay
* Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gstrtpvp8depay.h"
GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp8_depay_debug);
#define GST_CAT_DEFAULT gst_rtp_vp8_depay_debug
GST_BOILERPLATE (GstRtpVP8Depay, gst_rtp_vp8_depay, GstBaseRTPDepayload,
GST_TYPE_BASE_RTP_DEPAYLOAD);
static GstStaticPadTemplate gst_rtp_vp8_depay_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-vp8"));
static GstStaticPadTemplate gst_rtp_vp8_depay_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp, "
"payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ","
"clock-rate = (int) 90000,"
"media = (string) \"video\","
"encoding-name = (string) \"VP8-DRAFT-0-3-2\""));
static void
gst_rtp_vp8_depay_init (GstRtpVP8Depay * self, GstRtpVP8DepayClass * klass)
{
self->adapter = gst_adapter_new ();
self->started = FALSE;
}
static void gst_rtp_vp8_depay_dispose (GObject * object);
static GstBuffer *gst_rtp_vp8_depay_process (GstBaseRTPDepayload * depayload,
GstBuffer * buf);
static gboolean gst_rtp_vp8_depay_set_caps (GstBaseRTPDepayload * depayload,
GstCaps * caps);
static void
gst_rtp_vp8_depay_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_rtp_vp8_depay_sink_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_rtp_vp8_depay_src_template));
gst_element_class_set_details_simple (element_class, "RTP VP8 depayloader",
"Codec/Depayloader/Network/RTP",
"Extracts VP8 video from RTP packets)",
"Sjoerd Simons <sjoerd@luon.net>");
}
static void
gst_rtp_vp8_depay_class_init (GstRtpVP8DepayClass * gst_rtp_vp8_depay_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (gst_rtp_vp8_depay_class);
GstBaseRTPDepayloadClass *depay_class =
(GstBaseRTPDepayloadClass *) (gst_rtp_vp8_depay_class);
object_class->dispose = gst_rtp_vp8_depay_dispose;
depay_class->process = gst_rtp_vp8_depay_process;
depay_class->set_caps = gst_rtp_vp8_depay_set_caps;
GST_DEBUG_CATEGORY_INIT (gst_rtp_vp8_depay_debug, "rtpvp8depay", 0,
"VP8 Video RTP Depayloader");
}
static void
gst_rtp_vp8_depay_dispose (GObject * object)
{
GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (object);
if (self->adapter != NULL)
g_object_unref (self->adapter);
self->adapter = NULL;
/* release any references held by the object here */
if (G_OBJECT_CLASS (parent_class)->dispose)
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static GstBuffer *
gst_rtp_vp8_depay_process (GstBaseRTPDepayload * depay, GstBuffer * buf)
{
GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay);
GstBuffer *payload;
guint8 *data;
guint offset;
guint size = gst_rtp_buffer_get_payload_len (buf);
if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
GST_LOG_OBJECT (self, "Discontinuity, flushing adapter");
gst_adapter_clear (self->adapter);
self->started = FALSE;
}
if (G_UNLIKELY (size < 2))
goto too_small;
data = gst_rtp_buffer_get_payload (buf);
if (G_UNLIKELY (!self->started)) {
/* Check if this is the start of a VP8 frame, otherwise bail */
if ((data[0] & 0x1) == 0)
return NULL;
self->started = TRUE;
}
offset = 1;
if ((data[0] & 0x10) != 0) {
/* Skip Picture identifier bytes */
for (; (data[offset] & 0x80) != 0; offset++) {
/* should be at least one more pictureID byte and at least one byte in
* the vp8 payload */
if (offset + 2 >= size)
goto too_small;
}
offset++;
}
if (offset + 1 >= size)
goto too_small;
payload = gst_rtp_buffer_get_payload_subbuffer (buf, offset, -1);
gst_adapter_push (self->adapter, payload);
/* Marker indicates that it was the last rtp packet for this frame */
if (gst_rtp_buffer_get_marker (buf)) {
GstBuffer *out;
out = gst_adapter_take_buffer (self->adapter,
gst_adapter_available (self->adapter));
self->started = FALSE;
return out;
}
return NULL;
too_small:
GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring");
gst_adapter_clear (self->adapter);
self->started = FALSE;
return NULL;
}
static gboolean
gst_rtp_vp8_depay_set_caps (GstBaseRTPDepayload * depayload, GstCaps * caps)
{
GstCaps *srccaps = gst_caps_new_simple ("video/x-vp8",
"framerate", GST_TYPE_FRACTION, 0, 1,
NULL);
gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), srccaps);
gst_caps_unref (srccaps);
return TRUE;
}
gboolean
gst_rtp_vp8_depay_plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "rtpvp8depay",
GST_RANK_MARGINAL, GST_TYPE_RTP_VP8_DEPAY);
}

63
gst/rtp/gstrtpvp8depay.h Normal file
View file

@ -0,0 +1,63 @@
/*
* gst-rtp-vp8-depay.h - Header for GstRtpVP8Depay
* Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __GST_RTP_VP8_DEPAY_H__
#define __GST_RTP_VP8_DEPAY_H__
#include <glib-object.h>
#include <gst/base/gstadapter.h>
#include <gst/rtp/gstbasertpdepayload.h>
G_BEGIN_DECLS typedef struct _GstRtpVP8Depay GstRtpVP8Depay;
typedef struct _GstRtpVP8DepayClass GstRtpVP8DepayClass;
struct _GstRtpVP8DepayClass
{
GstBaseRTPDepayloadClass parent_class;
};
struct _GstRtpVP8Depay
{
GstBaseRTPDepayload parent;
GstAdapter *adapter;
gboolean started;
};
GType gst_rtp_vp8_depay_get_type (void);
/* TYPE MACROS */
#define GST_TYPE_RTP_VP8_DEPAY \
(gst_rtp_vp8_depay_get_type())
#define GST_RTP_VP8_DEPAY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_RTP_VP8_DEPAY, GstRtpVP8Depay))
#define GST_RTP_VP8_DEPAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_RTP_VP8_DEPAY, \
GstRtpVP8DepayClass))
#define GST_IS_RTP_VP8_DEPAY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_RTP_VP8_DEPAY))
#define GST_IS_RTP_VP8_DEPAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_RTP_VP8_DEPAY))
#define GST_RTP_VP8_DEPAY_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_VP8_DEPAY, \
GstRtpVP8DepayClass))
gboolean gst_rtp_vp8_depay_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* #ifndef __GST_RTP_VP8_DEPAY_H__ */

473
gst/rtp/gstrtpvp8pay.c Normal file
View file

@ -0,0 +1,473 @@
/*
* gst-rtp-vp8-pay.c - Source for GstRtpVP8Pay
* Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gst/base/gstbitreader.h>
#include <gst/rtp/gstrtppayloads.h>
#include <gst/rtp/gstrtpbuffer.h>
#include "gstrtpvp8pay.h"
#define FI_FRAG_UNFRAGMENTED 0x0
#define FI_FRAG_START 0x1
#define FI_FRAG_MIDDLE 0x2
#define FI_FRAG_END 0x3
GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp8_pay_debug);
#define GST_CAT_DEFAULT gst_rtp_vp8_pay_debug
GST_BOILERPLATE (GstRtpVP8Pay, gst_rtp_vp8_pay, GstBaseRTPPayload,
GST_TYPE_BASE_RTP_PAYLOAD);
static GstStaticPadTemplate gst_rtp_vp8_pay_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp, "
"payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ","
"clock-rate = (int) 90000, encoding-name = (string) \"VP8-DRAFT-0-3-2\""));
static GstStaticPadTemplate gst_rtp_vp8_pay_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-vp8"));
static void
gst_rtp_vp8_pay_init (GstRtpVP8Pay * obj, GstRtpVP8PayClass * klass)
{
}
static GstFlowReturn gst_rtp_vp8_pay_handle_buffer (GstBaseRTPPayload * payload,
GstBuffer * buffer);
static gboolean gst_rtp_vp8_pay_set_caps (GstBaseRTPPayload * payload,
GstCaps * caps);
static void
gst_rtp_vp8_pay_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_rtp_vp8_pay_sink_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_rtp_vp8_pay_src_template));
gst_element_class_set_details_simple (element_class, "RTP VP8 payloader",
"Codec/Payloader/Network/RTP",
"Puts VP8 video in RTP packets)", "Sjoerd Simons <sjoerd@luon.net>");
}
static void
gst_rtp_vp8_pay_class_init (GstRtpVP8PayClass * gst_rtp_vp8_pay_class)
{
GstBaseRTPPayloadClass *pay_class =
GST_BASE_RTP_PAYLOAD_CLASS (gst_rtp_vp8_pay_class);
pay_class->handle_buffer = gst_rtp_vp8_pay_handle_buffer;
pay_class->set_caps = gst_rtp_vp8_pay_set_caps;
GST_DEBUG_CATEGORY_INIT (gst_rtp_vp8_pay_debug, "rtpvp8pay", 0,
"VP8 Video RTP Payloader");
}
static gsize
gst_rtp_vp8_calc_payload_len (GstBaseRTPPayload * payload)
{
return gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU (payload) -
1, 0, 0);
}
/* When growing the vp8 header keep gst_rtp_vp8_calc_payload_len in sync */
static GstBuffer *
gst_rtp_vp8_create_header_buffer (gboolean start, gboolean mark, guint fi,
GstBuffer * in)
{
GstBuffer *out;
guint8 *p;
out = gst_rtp_buffer_new_allocate (1, 0, 0);
p = gst_rtp_buffer_get_payload (out);
/* Hardcode I = 0 and N = 0, only set FI and B */
p[0] = (fi & 0x3) << 1 | (start ? 1 : 0);
gst_rtp_buffer_set_marker (out, mark);
GST_BUFFER_DURATION (out) = GST_BUFFER_DURATION (in);
GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (in);
return out;
}
static gboolean
gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer)
{
GstBitReader *reader;
int i;
gboolean keyframe;
guint32 header_size;
guint8 version;
guint8 tmp8;
guint8 *data;
guint8 partitions;
reader = gst_bit_reader_new_from_buffer (buffer);
if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 3))
goto error;
data = GST_BUFFER_DATA (buffer);
self->is_keyframe = keyframe = ((data[0] & 0x1) == 0);
version = (data[0] >> 1) & 0x7;
/* keyframe, version and show_frame use 5 bits */
header_size = data[2] << 11 | data[1] << 3 | (data[0] >> 5);
/* Include the uncompressed data blob in the header */
header_size += keyframe ? 10 : 3;
if (!gst_bit_reader_skip (reader, 24))
goto error;
if (keyframe) {
/* check start tag: 0x9d 0x01 0x2a */
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 8) || tmp8 != 0x9d)
goto error;
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 8) || tmp8 != 0x01)
goto error;
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 8) || tmp8 != 0x2a)
goto error;
/* Skip horizontal size code (16 bits) vertical size code (16 bits),
* color space (1 bit) and clamping type (1 bit) */
if (!gst_bit_reader_skip (reader, 34))
goto error;
}
/* segmentation_enabled */
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1))
goto error;
if (tmp8 != 0) {
gboolean update_mb_segmentation_map;
gboolean update_segment_feature_data;
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 2))
goto error;
update_mb_segmentation_map = (tmp8 & 0x2) != 0;
update_segment_feature_data = (tmp8 & 0x1) != 0;
if (update_segment_feature_data) {
/* skip segment feature mode */
if (!gst_bit_reader_skip (reader, 1))
goto error;
for (i = 0; i < 4; i++) {
/* quantizer update */
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1))
goto error;
if (tmp8 != 0) {
/* skip quantizer value (7 bits) and sign (1 bit) */
if (!gst_bit_reader_skip (reader, 8))
goto error;
}
}
for (i = 0; i < 4; i++) {
/* loop filter update */
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1))
goto error;
if (tmp8 != 0) {
/* skip lf update value (6 bits) and sign (1 bit) */
if (!gst_bit_reader_skip (reader, 7))
goto error;
}
}
}
if (update_mb_segmentation_map) {
for (i = 0; i < 3; i++) {
/* segment prob update */
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1))
goto error;
if (tmp8 != 0) {
/* skip segment prob */
if (!gst_bit_reader_skip (reader, 8))
goto error;
}
}
}
}
/* skip filter type (1 bit), loop filter level (6 bits) and
* sharpness level (3 bits) */
if (!gst_bit_reader_skip (reader, 10))
goto error;
/* loop_filter_adj_enabled */
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1))
goto error;
if (tmp8 != 0) {
/* loop filter adj enabled */
/* mode_ref_lf_delta_update */
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1))
goto error;
if (tmp8 != 0) {
/* mode_ref_lf_data_update */
int i;
for (i = 0; i < 8; i++) {
/* 8 updates, 1 bit indicate whether there is one and if follow by a
* 7 bit update */
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1))
goto error;
if (tmp8 != 0) {
/* skip delta magnitude (6 bits) and sign (1 bit) */
if (!gst_bit_reader_skip (reader, 7))
goto error;
}
}
}
}
if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 2))
goto error;
self->n_partitions = partitions = 1 << tmp8;
/* Check if things are still sensible */
if (header_size + (partitions - 1) * 3 >= GST_BUFFER_SIZE (buffer))
goto error;
/* partition data is right after the frame header */
data = GST_BUFFER_DATA (buffer) + header_size;
self->partition_offset[0] = header_size + (partitions - 1) * 3;
/* Include partition data in the header for RTP purposes */
self->header_size = self->partition_offset[0];
for (i = 0; i < (partitions - 1); i++) {
guint size = (data[2] << 16 | data[1] << 8 | data[0]);
data += 3;
self->partition_size[i] = size;
self->partition_offset[i + 1] = self->partition_offset[i] + size;
}
/* Check that our partition offsets and sizes don't go outsize the buffer
* size. */
if (self->partition_offset[i] >= GST_BUFFER_SIZE (buffer))
goto error;
self->partition_size[i] = GST_BUFFER_SIZE (buffer)
- self->partition_offset[i];
self->partition_offset[i + 1] = GST_BUFFER_SIZE (buffer);
gst_bit_reader_free (reader);
return TRUE;
error:
GST_DEBUG ("Failed to parse frame");
gst_bit_reader_free (reader);
return FALSE;
}
static guint
gst_rtp_vp8_fit_partitions (GstRtpVP8Pay * self, gint first, gsize available)
{
guint num = 0;
int i;
g_assert (first < self->n_partitions);
if (first < 0) {
if (self->header_size > available)
return 0;
available -= self->header_size;
num++;
first = 0;
}
for (i = first;
i < self->n_partitions && self->partition_size[i] < available; i++) {
num++;
available -= self->partition_size[i];
}
return num;
}
static GstBuffer *
gst_rtp_vp8_create_sub (GstRtpVP8Pay * self,
GstBuffer * buffer, gint current, guint num)
{
guint offset = 0;
guint size;
if (current >= 0) {
offset = self->partition_offset[current];
}
size = self->partition_offset[current + num] - offset;
return gst_buffer_create_sub (buffer, offset, size);
}
static guint
gst_rtp_vp8_payload_next (GstRtpVP8Pay * self,
GstBufferListIterator * it, gint first, GstBuffer * buffer)
{
guint num;
GstBuffer *header;
GstBuffer *sub;
gboolean mark;
gsize available = gst_rtp_vp8_calc_payload_len (GST_BASE_RTP_PAYLOAD (self));
g_assert (first < 8);
/* How many partitions can we fit */
num = gst_rtp_vp8_fit_partitions (self, first, available);
if (num > 0) {
mark = (first + num == self->n_partitions);
/* whole set of partitions, payload them and done */
header = gst_rtp_vp8_create_header_buffer (first == -1, mark,
FI_FRAG_UNFRAGMENTED, buffer);
sub = gst_rtp_vp8_create_sub (self, buffer, first, num);
gst_buffer_list_iterator_add_group (it);
gst_buffer_list_iterator_add (it, header);
gst_buffer_list_iterator_add (it, sub);
} else {
/* Fragmented packets */
guint left;
guint offset;
if (first >= 0) {
offset = self->partition_offset[first];
left = self->partition_size[first];
} else {
offset = 0;
left = self->header_size;
}
header = gst_rtp_vp8_create_header_buffer (first == -1, FALSE,
FI_FRAG_START, buffer);
sub = gst_buffer_create_sub (buffer, offset, available);
offset += available;
gst_buffer_list_iterator_add_group (it);
gst_buffer_list_iterator_add (it, header);
gst_buffer_list_iterator_add (it, sub);
left -= available;
for (; left > available; left -= available) {
header = gst_rtp_vp8_create_header_buffer (first == -1, FALSE,
FI_FRAG_MIDDLE, buffer);
sub = gst_buffer_create_sub (buffer, offset, available);
offset += available;
gst_buffer_list_iterator_add_group (it);
gst_buffer_list_iterator_add (it, header);
gst_buffer_list_iterator_add (it, sub);
}
mark = (first + 1 == self->n_partitions);
header = gst_rtp_vp8_create_header_buffer (first == -1, mark,
FI_FRAG_END, buffer);
sub = gst_buffer_create_sub (buffer, offset, left);
gst_buffer_list_iterator_add_group (it);
gst_buffer_list_iterator_add (it, header);
gst_buffer_list_iterator_add (it, sub);
return 1;
}
return num;
}
static GstFlowReturn
gst_rtp_vp8_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buffer)
{
GstRtpVP8Pay *self = GST_RTP_VP8_PAY (payload);
GstFlowReturn ret;
GstBufferList *list;
GstBufferListIterator *it;
gint current;
if (G_UNLIKELY (!gst_rtp_vp8_pay_parse_frame (self, buffer))) {
/* FIXME throw flow error */
g_message ("Failed to parse frame");
return GST_FLOW_ERROR;
}
list = gst_buffer_list_new ();
it = gst_buffer_list_iterate (list);
for (current = -1; current < self->n_partitions;) {
guint n;
n = gst_rtp_vp8_payload_next (self, it, current, buffer);
current += n;
}
ret = gst_basertppayload_push_list (payload, list);
gst_buffer_list_iterator_free (it);
return ret;
}
static gboolean
gst_rtp_vp8_pay_set_caps (GstBaseRTPPayload * payload, GstCaps * caps)
{
gst_basertppayload_set_options (payload, "video", TRUE,
"VP8-DRAFT-0-3-2", 90000);
return gst_basertppayload_set_outcaps (payload, NULL);
}
gboolean
gst_rtp_vp8_pay_plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "rtpvp8pay",
GST_RANK_MARGINAL, GST_TYPE_RTP_VP8_PAY);
}

65
gst/rtp/gstrtpvp8pay.h Normal file
View file

@ -0,0 +1,65 @@
/*
* gst-rtp-vp8-pay.h - Header for GstRtpVP8Pay
* Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __GST_RTP_VP8_PAY_H__
#define __GST_RTP_VP8_PAY_H__
#include <glib-object.h>
#include <gst/base/gstadapter.h>
#include <gst/rtp/gstbasertppayload.h>
G_BEGIN_DECLS typedef struct _GstRtpVP8Pay GstRtpVP8Pay;
typedef struct _GstRtpVP8PayClass GstRtpVP8PayClass;
struct _GstRtpVP8PayClass
{
GstBaseRTPPayloadClass parent_class;
};
struct _GstRtpVP8Pay
{
GstBaseRTPPayload parent;
gboolean is_keyframe;
gint n_partitions;
guint header_size;
/* Add the end offset for easier implementation */
guint partition_offset[9];
guint partition_size[8];
};
GType gst_rtp_vp8_pay_get_type (void);
/* TYPE MACROS */
#define GST_TYPE_RTP_VP8_PAY \
(gst_rtp_vp8_pay_get_type())
#define GST_RTP_VP8_PAY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_RTP_VP8_PAY, GstRtpVP8Pay))
#define GST_RTP_VP8_PAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_RTP_VP8_PAY, GstRtpVP8PayClass))
#define GST_IS_RTP_VP8_PAY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_RTP_VP8_PAY))
#define GST_IS_RTP_VP8_PAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_RTP_VP8_PAY))
#define GST_RTP_VP8_PAY_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_VP8_PAY, GstRtpVP8PayClass))
gboolean gst_rtp_vp8_pay_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* #ifndef __GST_RTP_VP8_PAY_H__ */