mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 18:50:48 +00:00
tests/check/Makefile.am (check_vorbis): Add pipelines/vorbisenc.
Original commit message from CVS: 2006-01-30 Andy Wingo <wingo@pobox.com> * tests/check/Makefile.am (check_vorbis): Add pipelines/vorbisenc. * ext/vorbis/vorbisenc.c (gst_vorbisenc_buffer_from_packet): Logic updated to timestamp from the first sample, not the last. (gst_vorbisenc_buffer_from_header_packet): New function, takes special care of granulepos and timestamp for header packets. (gst_vorbisenc_chain): Reflow, fix some leaks, and handle the case when the first buffer has a nonzero timestamp. * ext/vorbis/vorbisenc.h (GstVorbisEnc.granulepos_offset) (GstVorbisEnc.subgranule_offset): New members. Take care of the case when the first audio buffer we get has a nonzero timestamp. (GstVorbisEnc.next_ts): Renamed from prev_ts, because now we properly timestamp vorbis buffers with the time of the first sample, not the last. * ext/vorbis/vorbisenc.c (granulepos_to_clocktime): Renamed from vorbis_granule_time_copy -- now it takes the granule/subgranule offset into account. * tests/check/pipelines/vorbisenc.c: New test for correctness of timestamps, durations, and granulepos on buffers produced by vorbisenc.
This commit is contained in:
parent
6757e87c91
commit
0ad84fae5d
5 changed files with 511 additions and 89 deletions
26
ChangeLog
26
ChangeLog
|
@ -1,3 +1,29 @@
|
|||
2006-01-30 Andy Wingo <wingo@pobox.com>
|
||||
|
||||
* tests/check/Makefile.am (check_vorbis): Add pipelines/vorbisenc.
|
||||
|
||||
* ext/vorbis/vorbisenc.c (gst_vorbisenc_buffer_from_packet): Logic
|
||||
updated to timestamp from the first sample, not the last.
|
||||
(gst_vorbisenc_buffer_from_header_packet): New function, takes
|
||||
special care of granulepos and timestamp for header packets.
|
||||
(gst_vorbisenc_chain): Reflow, fix some leaks, and handle the case
|
||||
when the first buffer has a nonzero timestamp.
|
||||
|
||||
* ext/vorbis/vorbisenc.h (GstVorbisEnc.granulepos_offset)
|
||||
(GstVorbisEnc.subgranule_offset): New members. Take care of the
|
||||
case when the first audio buffer we get has a nonzero timestamp.
|
||||
(GstVorbisEnc.next_ts): Renamed from prev_ts, because now we
|
||||
properly timestamp vorbis buffers with the time of the first
|
||||
sample, not the last.
|
||||
|
||||
* ext/vorbis/vorbisenc.c (granulepos_to_clocktime): Renamed from
|
||||
vorbis_granule_time_copy -- now it takes the granule/subgranule
|
||||
offset into account.
|
||||
|
||||
* tests/check/pipelines/vorbisenc.c: New test for correctness of
|
||||
timestamps, durations, and granulepos on buffers produced by
|
||||
vorbisenc.
|
||||
|
||||
2006-01-30 Jan Schmidt <thaytan@mad.scientist.com>
|
||||
|
||||
* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
|
||||
|
|
|
@ -98,17 +98,14 @@ enum
|
|||
|
||||
static GstFlowReturn gst_vorbisenc_output_buffers (GstVorbisEnc * vorbisenc);
|
||||
|
||||
/* FIXME:
|
||||
* vorbis_granule_time was added between 1.0 and 1.0.1; it's too silly
|
||||
* to require a new version for such a simple function, but once we move
|
||||
* beyond 1.0 for other reasons we can remove this copy */
|
||||
|
||||
static double
|
||||
vorbis_granule_time_copy (vorbis_dsp_state * v, ogg_int64_t granulepos)
|
||||
static GstClockTime
|
||||
granulepos_to_clocktime (GstVorbisEnc * vorbisenc, ogg_int64_t granulepos)
|
||||
{
|
||||
if (granulepos >= 0)
|
||||
return ((double) granulepos / v->vi->rate);
|
||||
return (-1);
|
||||
return gst_util_uint64_scale ((guint64) granulepos
|
||||
+ vorbisenc->granulepos_offset, GST_SECOND, vorbisenc->frequency)
|
||||
+ vorbisenc->subgranule_offset;
|
||||
return GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -549,7 +546,6 @@ gst_vorbisenc_init (GstVorbisEnc * vorbisenc)
|
|||
vorbisenc->quality = QUALITY_DEFAULT;
|
||||
vorbisenc->quality_set = FALSE;
|
||||
vorbisenc->last_message = NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -770,7 +766,7 @@ gst_vorbisenc_setup (GstVorbisEnc * vorbisenc)
|
|||
vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi);
|
||||
vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb);
|
||||
|
||||
vorbisenc->prev_ts = 0;
|
||||
vorbisenc->next_ts = 0;
|
||||
|
||||
vorbisenc->setup = TRUE;
|
||||
|
||||
|
@ -808,18 +804,40 @@ gst_vorbisenc_buffer_from_packet (GstVorbisEnc * vorbisenc, ogg_packet * packet)
|
|||
outbuf = gst_buffer_new_and_alloc (packet->bytes);
|
||||
memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
|
||||
GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out;
|
||||
GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos;
|
||||
GST_BUFFER_TIMESTAMP (outbuf) =
|
||||
vorbis_granule_time_copy (&vorbisenc->vd,
|
||||
packet->granulepos) * GST_SECOND;
|
||||
GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos +
|
||||
vorbisenc->granulepos_offset;
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = vorbisenc->next_ts;
|
||||
|
||||
/* need to pass in an unadjusted granulepos here */
|
||||
vorbisenc->next_ts = granulepos_to_clocktime (vorbisenc, packet->granulepos);
|
||||
|
||||
GST_BUFFER_DURATION (outbuf) =
|
||||
GST_BUFFER_TIMESTAMP (outbuf) - vorbisenc->prev_ts;
|
||||
vorbisenc->prev_ts = GST_BUFFER_TIMESTAMP (outbuf);
|
||||
vorbisenc->next_ts - GST_BUFFER_TIMESTAMP (outbuf);
|
||||
|
||||
GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
|
||||
return outbuf;
|
||||
}
|
||||
|
||||
/* the same as above, but different logic for setting timestamp and granulepos
|
||||
* */
|
||||
static GstBuffer *
|
||||
gst_vorbisenc_buffer_from_header_packet (GstVorbisEnc * vorbisenc,
|
||||
ogg_packet * packet)
|
||||
{
|
||||
GstBuffer *outbuf;
|
||||
|
||||
outbuf = gst_buffer_new_and_alloc (packet->bytes);
|
||||
memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
|
||||
GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out;
|
||||
GST_BUFFER_OFFSET_END (outbuf) = 0;
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
|
||||
GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
|
||||
|
||||
GST_DEBUG ("created header packet buffer, %d bytes",
|
||||
GST_BUFFER_SIZE (outbuf));
|
||||
return outbuf;
|
||||
}
|
||||
|
||||
/* push out the buffer and do internal bookkeeping */
|
||||
static GstFlowReturn
|
||||
gst_vorbisenc_push_buffer (GstVorbisEnc * vorbisenc, GstBuffer * buffer)
|
||||
|
@ -913,97 +931,117 @@ gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event)
|
|||
static GstFlowReturn
|
||||
gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (buffer);
|
||||
GstVorbisEnc *vorbisenc;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
gfloat *data;
|
||||
gulong size;
|
||||
gulong i, j;
|
||||
float **vorbis_buffer;
|
||||
|
||||
vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
|
||||
|
||||
{
|
||||
gfloat *data;
|
||||
gulong size;
|
||||
gulong i, j;
|
||||
float **buffer;
|
||||
if (!vorbisenc->setup)
|
||||
goto not_setup;
|
||||
|
||||
if (!vorbisenc->setup) {
|
||||
gst_buffer_unref (buf);
|
||||
GST_ELEMENT_ERROR (vorbisenc, CORE, NEGOTIATION, (NULL),
|
||||
("encoder not initialized (input is not audio?)"));
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
if (!vorbisenc->header_sent) {
|
||||
/* Vorbis streams begin with three headers; the initial header (with
|
||||
most of the codec setup parameters) which is mandated by the Ogg
|
||||
bitstream spec. The second header holds any comment fields. The
|
||||
third header holds the bitstream codebook. We merely need to
|
||||
make the headers, then pass them to libvorbis one at a time;
|
||||
libvorbis handles the additional Ogg bitstream constraints */
|
||||
ogg_packet header;
|
||||
ogg_packet header_comm;
|
||||
ogg_packet header_code;
|
||||
GstBuffer *buf1, *buf2, *buf3;
|
||||
GstCaps *caps;
|
||||
|
||||
if (!vorbisenc->header_sent) {
|
||||
/* Vorbis streams begin with three headers; the initial header (with
|
||||
most of the codec setup parameters) which is mandated by the Ogg
|
||||
bitstream spec. The second header holds any comment fields. The
|
||||
third header holds the bitstream codebook. We merely need to
|
||||
make the headers, then pass them to libvorbis one at a time;
|
||||
libvorbis handles the additional Ogg bitstream constraints */
|
||||
ogg_packet header;
|
||||
ogg_packet header_comm;
|
||||
ogg_packet header_code;
|
||||
GstBuffer *buf1, *buf2, *buf3;
|
||||
GstCaps *caps;
|
||||
/* first, make sure header buffers get timestamp == 0 */
|
||||
vorbisenc->next_ts = 0;
|
||||
vorbisenc->granulepos_offset = 0;
|
||||
vorbisenc->subgranule_offset = 0;
|
||||
|
||||
GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets");
|
||||
gst_vorbisenc_set_metadata (vorbisenc);
|
||||
vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header,
|
||||
&header_comm, &header_code);
|
||||
GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets");
|
||||
gst_vorbisenc_set_metadata (vorbisenc);
|
||||
vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header,
|
||||
&header_comm, &header_code);
|
||||
|
||||
/* create header buffers */
|
||||
buf1 = gst_vorbisenc_buffer_from_packet (vorbisenc, &header);
|
||||
buf2 = gst_vorbisenc_buffer_from_packet (vorbisenc, &header_comm);
|
||||
buf3 = gst_vorbisenc_buffer_from_packet (vorbisenc, &header_code);
|
||||
/* create header buffers */
|
||||
buf1 = gst_vorbisenc_buffer_from_header_packet (vorbisenc, &header);
|
||||
buf2 = gst_vorbisenc_buffer_from_header_packet (vorbisenc, &header_comm);
|
||||
buf3 = gst_vorbisenc_buffer_from_header_packet (vorbisenc, &header_code);
|
||||
|
||||
/* mark and put on caps */
|
||||
caps = gst_pad_get_caps (vorbisenc->srcpad);
|
||||
caps = gst_vorbisenc_set_header_on_caps (caps, buf1, buf2, buf3);
|
||||
/* mark and put on caps */
|
||||
caps = gst_pad_get_caps (vorbisenc->srcpad);
|
||||
caps = gst_vorbisenc_set_header_on_caps (caps, buf1, buf2, buf3);
|
||||
|
||||
/* negotiate with these caps */
|
||||
GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
|
||||
gst_pad_set_caps (vorbisenc->srcpad, caps);
|
||||
/* negotiate with these caps */
|
||||
GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
|
||||
gst_pad_set_caps (vorbisenc->srcpad, caps);
|
||||
|
||||
gst_buffer_set_caps (buf1, caps);
|
||||
gst_buffer_set_caps (buf2, caps);
|
||||
gst_buffer_set_caps (buf3, caps);
|
||||
gst_buffer_set_caps (buf1, caps);
|
||||
gst_buffer_set_caps (buf2, caps);
|
||||
gst_buffer_set_caps (buf3, caps);
|
||||
|
||||
/* push out buffers */
|
||||
if ((ret = gst_vorbisenc_push_buffer (vorbisenc, buf1)) != GST_FLOW_OK)
|
||||
goto done;
|
||||
if ((ret = gst_vorbisenc_push_buffer (vorbisenc, buf2)) != GST_FLOW_OK)
|
||||
goto done;
|
||||
if ((ret = gst_vorbisenc_push_buffer (vorbisenc, buf3)) != GST_FLOW_OK)
|
||||
goto done;
|
||||
/* push out buffers */
|
||||
if ((ret = gst_vorbisenc_push_buffer (vorbisenc, buf1)) != GST_FLOW_OK)
|
||||
goto failed_header_push;
|
||||
if ((ret = gst_vorbisenc_push_buffer (vorbisenc, buf2)) != GST_FLOW_OK)
|
||||
goto failed_header_push;
|
||||
if ((ret = gst_vorbisenc_push_buffer (vorbisenc, buf3)) != GST_FLOW_OK)
|
||||
goto failed_header_push;
|
||||
|
||||
vorbisenc->header_sent = TRUE;
|
||||
}
|
||||
|
||||
/* data to encode */
|
||||
data = (gfloat *) GST_BUFFER_DATA (buf);
|
||||
size = GST_BUFFER_SIZE (buf) / (vorbisenc->channels * sizeof (float));
|
||||
/* now adjust starting granulepos accordingly if the buffer's timestamp is
|
||||
nonzero */
|
||||
vorbisenc->next_ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||
vorbisenc->granulepos_offset = gst_util_uint64_scale
|
||||
(GST_BUFFER_TIMESTAMP (buffer), vorbisenc->frequency, GST_SECOND);
|
||||
vorbisenc->subgranule_offset = 0;
|
||||
vorbisenc->subgranule_offset =
|
||||
vorbisenc->next_ts - granulepos_to_clocktime (vorbisenc, 0);
|
||||
|
||||
/* expose the buffer to submit data */
|
||||
buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);
|
||||
|
||||
/* uninterleave samples */
|
||||
for (i = 0; i < size; i++) {
|
||||
for (j = 0; j < vorbisenc->channels; j++) {
|
||||
buffer[j][i] = *data++;
|
||||
}
|
||||
}
|
||||
|
||||
/* tell the library how much we actually submitted */
|
||||
vorbis_analysis_wrote (&vorbisenc->vd, size);
|
||||
|
||||
vorbisenc->samples_in += size;
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
vorbisenc->header_sent = TRUE;
|
||||
}
|
||||
|
||||
/* data to encode */
|
||||
data = (gfloat *) GST_BUFFER_DATA (buffer);
|
||||
size = GST_BUFFER_SIZE (buffer) / (vorbisenc->channels * sizeof (float));
|
||||
|
||||
/* expose the buffer to submit data */
|
||||
vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);
|
||||
|
||||
/* deinterleave samples, write the buffer data */
|
||||
for (i = 0; i < size; i++) {
|
||||
for (j = 0; j < vorbisenc->channels; j++) {
|
||||
vorbis_buffer[j][i] = *data++;
|
||||
}
|
||||
}
|
||||
|
||||
/* tell the library how much we actually submitted */
|
||||
vorbis_analysis_wrote (&vorbisenc->vd, size);
|
||||
|
||||
vorbisenc->samples_in += size;
|
||||
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
ret = gst_vorbisenc_output_buffers (vorbisenc);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
|
||||
/* error cases */
|
||||
not_setup:
|
||||
{
|
||||
gst_buffer_unref (buffer);
|
||||
GST_ELEMENT_ERROR (vorbisenc, CORE, NEGOTIATION, (NULL),
|
||||
("encoder not initialized (input is not audio?)"));
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
failed_header_push:
|
||||
{
|
||||
gst_buffer_unref (buffer);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
|
|
@ -69,7 +69,9 @@ struct _GstVorbisEnc {
|
|||
|
||||
guint64 samples_in;
|
||||
guint64 bytes_out;
|
||||
GstClockTime prev_ts;
|
||||
GstClockTime next_ts;
|
||||
guint64 granulepos_offset;
|
||||
gint64 subgranule_offset;
|
||||
|
||||
GstTagList * tags;
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ $(CHECK_REGISTRY):
|
|||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
if USE_VORBIS
|
||||
check_vorbis = elements/vorbisdec
|
||||
check_vorbis = elements/vorbisdec pipelines/vorbisenc
|
||||
else
|
||||
check_vorbis =
|
||||
endif
|
||||
|
|
356
tests/check/pipelines/vorbisenc.c
Normal file
356
tests/check/pipelines/vorbisenc.c
Normal file
|
@ -0,0 +1,356 @@
|
|||
/* GStreamer
|
||||
*
|
||||
* unit test for vorbisenc
|
||||
*
|
||||
* Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <gst/check/gstcheck.h>
|
||||
|
||||
#define TIMESTAMP_OFFSET G_GUINT64_CONSTANT(3249870963)
|
||||
|
||||
static GCond *cond = NULL;
|
||||
static GMutex *lock = NULL;
|
||||
static GstBuffer *buf = NULL;
|
||||
static gulong id;
|
||||
|
||||
static gboolean
|
||||
buffer_probe (GstPad * pad, GstBuffer * buffer, gpointer unused)
|
||||
{
|
||||
g_mutex_lock (lock);
|
||||
|
||||
while (buf != NULL)
|
||||
g_cond_wait (cond, lock);
|
||||
|
||||
buf = gst_buffer_ref (buffer);
|
||||
|
||||
g_cond_signal (cond);
|
||||
|
||||
g_mutex_unlock (lock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
start_pipeline (GstElement * bin, GstPad * pad)
|
||||
{
|
||||
id = gst_pad_add_buffer_probe (pad, G_CALLBACK (buffer_probe), NULL);
|
||||
|
||||
cond = g_cond_new ();
|
||||
lock = g_mutex_new ();
|
||||
|
||||
gst_element_set_state (bin, GST_STATE_PLAYING);
|
||||
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
get_buffer (GstElement * bin, GstPad * pad)
|
||||
{
|
||||
GstBuffer *ret;
|
||||
|
||||
g_mutex_lock (lock);
|
||||
|
||||
while (buf == NULL)
|
||||
g_cond_wait (cond, lock);
|
||||
|
||||
ret = buf;
|
||||
buf = NULL;
|
||||
|
||||
g_cond_signal (cond);
|
||||
|
||||
g_mutex_unlock (lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
stop_pipeline (GstElement * bin, GstPad * pad)
|
||||
{
|
||||
g_mutex_lock (lock);
|
||||
if (buf)
|
||||
gst_buffer_unref (buf);
|
||||
buf = NULL;
|
||||
gst_pad_remove_buffer_probe (pad, (guint) id);
|
||||
id = 0;
|
||||
g_cond_signal (cond);
|
||||
g_mutex_unlock (lock);
|
||||
|
||||
gst_element_set_state (bin, GST_STATE_NULL);
|
||||
|
||||
g_mutex_lock (lock);
|
||||
if (buf)
|
||||
gst_buffer_unref (buf);
|
||||
buf = NULL;
|
||||
g_mutex_unlock (lock);
|
||||
|
||||
g_mutex_free (lock);
|
||||
g_cond_free (cond);
|
||||
|
||||
lock = NULL;
|
||||
cond = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
check_buffer_timestamp (GstBuffer * buffer, GstClockTime timestamp)
|
||||
{
|
||||
fail_unless (GST_BUFFER_TIMESTAMP (buffer) == timestamp,
|
||||
"expected timestamp %" GST_TIME_FORMAT
|
||||
", but got timestamp %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (timestamp), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
|
||||
}
|
||||
|
||||
static void
|
||||
check_buffer_duration (GstBuffer * buffer, GstClockTime duration)
|
||||
{
|
||||
fail_unless (GST_BUFFER_DURATION (buffer) == duration,
|
||||
"expected duration %" GST_TIME_FORMAT
|
||||
", but got duration %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (duration), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
|
||||
}
|
||||
|
||||
static void
|
||||
check_buffer_granulepos (GstBuffer * buffer, GstClockTime granulepos)
|
||||
{
|
||||
fail_unless (GST_BUFFER_OFFSET_END (buffer) == granulepos,
|
||||
"expected granulepos %" G_GUINT64_FORMAT
|
||||
", but got granulepos %" G_GUINT64_FORMAT,
|
||||
granulepos, GST_BUFFER_OFFSET_END (buffer));
|
||||
}
|
||||
|
||||
/* this check is here to check that the granulepos we derive from the timestamp
|
||||
is about correct. This is "about correct" because you can't precisely go from
|
||||
timestamp to granulepos due to the downward-rounding characteristics of
|
||||
gst_util_uint64_scale, so you check if granulepos is equal to the number, or
|
||||
the number plus one. */
|
||||
static void
|
||||
check_buffer_granulepos_from_endtime (GstBuffer * buffer, GstClockTime endtime)
|
||||
{
|
||||
GstClockTime granulepos, expected;
|
||||
|
||||
granulepos = GST_BUFFER_OFFSET_END (buffer);
|
||||
expected = gst_util_uint64_scale (endtime, 44100, GST_SECOND);
|
||||
|
||||
fail_unless (granulepos == expected || granulepos == expected + 1,
|
||||
"expected granulepos %" G_GUINT64_FORMAT
|
||||
" or %" G_GUINT64_FORMAT
|
||||
", but got granulepos %" G_GUINT64_FORMAT,
|
||||
expected, expected + 1, granulepos);
|
||||
}
|
||||
|
||||
GST_START_TEST (test_granulepos_offset)
|
||||
{
|
||||
GstElement *bin;
|
||||
GstPad *pad;
|
||||
gchar *pipe_str;
|
||||
GstBuffer *buffer;
|
||||
GError *error = NULL;
|
||||
GstClockTime timestamp;
|
||||
|
||||
pipe_str = g_strdup_printf ("audiotestsrc timestamp-offset=%" G_GUINT64_FORMAT
|
||||
" ! audio/x-raw-int,rate=44100"
|
||||
" ! audioconvert ! vorbisenc ! fakesink", TIMESTAMP_OFFSET);
|
||||
|
||||
bin = gst_parse_launch (pipe_str, &error);
|
||||
fail_unless (bin != NULL, "Error parsing pipeline: %s",
|
||||
error ? error->message : "(invalid error)");
|
||||
g_free (pipe_str);
|
||||
|
||||
/* get the pad */
|
||||
{
|
||||
GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
|
||||
|
||||
fail_unless (sink != NULL, "Could not get fakesink out of bin");
|
||||
pad = gst_element_get_pad (sink, "sink");
|
||||
fail_unless (pad != NULL, "Could not get pad out of fakesink");
|
||||
gst_object_unref (sink);
|
||||
}
|
||||
|
||||
start_pipeline (bin, pad);
|
||||
|
||||
/* header packets should have timestamp == NONE, granulepos 0 */
|
||||
buffer = get_buffer (bin, pad);
|
||||
check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_granulepos (buffer, 0);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
buffer = get_buffer (bin, pad);
|
||||
check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_granulepos (buffer, 0);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
buffer = get_buffer (bin, pad);
|
||||
check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_granulepos (buffer, 0);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
{
|
||||
GstClockTime next_timestamp, last_granulepos;
|
||||
|
||||
/* first buffer should have timestamp of TIMESTAMP_OFFSET, granulepos to
|
||||
* match the timestamp of the end of the last sample in the output buffer.
|
||||
* Note that one cannot go timestamp->granulepos->timestamp and get the same
|
||||
* value due to loss of precision with granulepos. vorbisenc does take care
|
||||
* to timestamp correctly based on the offset of the input data however, so
|
||||
* it does do sub-granulepos timestamping. */
|
||||
buffer = get_buffer (bin, pad);
|
||||
last_granulepos = GST_BUFFER_OFFSET_END (buffer);
|
||||
check_buffer_timestamp (buffer, TIMESTAMP_OFFSET);
|
||||
/* don't really have a good way of checking duration... */
|
||||
check_buffer_granulepos_from_endtime (buffer,
|
||||
TIMESTAMP_OFFSET + GST_BUFFER_DURATION (buffer));
|
||||
|
||||
next_timestamp = TIMESTAMP_OFFSET + GST_BUFFER_DURATION (buffer);
|
||||
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
/* check continuity with the next buffer */
|
||||
buffer = get_buffer (bin, pad);
|
||||
check_buffer_timestamp (buffer, next_timestamp);
|
||||
check_buffer_duration (buffer,
|
||||
gst_util_uint64_scale (GST_BUFFER_OFFSET_END (buffer), GST_SECOND,
|
||||
44100)
|
||||
- gst_util_uint64_scale (last_granulepos, GST_SECOND, 44100));
|
||||
check_buffer_granulepos_from_endtime (buffer,
|
||||
next_timestamp + GST_BUFFER_DURATION (buffer));
|
||||
|
||||
gst_buffer_unref (buffer);
|
||||
}
|
||||
|
||||
stop_pipeline (bin, pad);
|
||||
|
||||
gst_object_unref (pad);
|
||||
gst_object_unref (bin);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_timestamps)
|
||||
{
|
||||
GstElement *bin;
|
||||
GstPad *pad;
|
||||
gchar *pipe_str;
|
||||
GstBuffer *buffer;
|
||||
GError *error = NULL;
|
||||
GstClockTime timestamp;
|
||||
|
||||
pipe_str = g_strdup_printf ("audiotestsrc"
|
||||
" ! audio/x-raw-int,rate=44100" " ! audioconvert ! vorbisenc ! fakesink");
|
||||
|
||||
bin = gst_parse_launch (pipe_str, &error);
|
||||
fail_unless (bin != NULL, "Error parsing pipeline: %s",
|
||||
error ? error->message : "(invalid error)");
|
||||
g_free (pipe_str);
|
||||
|
||||
/* get the pad */
|
||||
{
|
||||
GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
|
||||
|
||||
fail_unless (sink != NULL, "Could not get fakesink out of bin");
|
||||
pad = gst_element_get_pad (sink, "sink");
|
||||
fail_unless (pad != NULL, "Could not get pad out of fakesink");
|
||||
gst_object_unref (sink);
|
||||
}
|
||||
|
||||
start_pipeline (bin, pad);
|
||||
|
||||
/* check header packets */
|
||||
buffer = get_buffer (bin, pad);
|
||||
check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_granulepos (buffer, 0);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
buffer = get_buffer (bin, pad);
|
||||
check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_granulepos (buffer, 0);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
buffer = get_buffer (bin, pad);
|
||||
check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
|
||||
check_buffer_granulepos (buffer, 0);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
{
|
||||
GstClockTime next_timestamp, last_granulepos;
|
||||
|
||||
/* first buffer has timestamp 0 */
|
||||
buffer = get_buffer (bin, pad);
|
||||
last_granulepos = GST_BUFFER_OFFSET_END (buffer);
|
||||
check_buffer_timestamp (buffer, 0);
|
||||
/* don't really have a good way of checking duration... */
|
||||
check_buffer_granulepos_from_endtime (buffer, GST_BUFFER_DURATION (buffer));
|
||||
|
||||
next_timestamp = GST_BUFFER_DURATION (buffer);
|
||||
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
/* check continuity with the next buffer */
|
||||
buffer = get_buffer (bin, pad);
|
||||
check_buffer_timestamp (buffer, next_timestamp);
|
||||
check_buffer_duration (buffer,
|
||||
gst_util_uint64_scale (GST_BUFFER_OFFSET_END (buffer), GST_SECOND,
|
||||
44100)
|
||||
- gst_util_uint64_scale (last_granulepos, GST_SECOND, 44100));
|
||||
check_buffer_granulepos_from_endtime (buffer,
|
||||
next_timestamp + GST_BUFFER_DURATION (buffer));
|
||||
|
||||
gst_buffer_unref (buffer);
|
||||
}
|
||||
|
||||
stop_pipeline (bin, pad);
|
||||
|
||||
gst_object_unref (pad);
|
||||
gst_object_unref (bin);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
Suite *
|
||||
vorbisenc_suite (void)
|
||||
{
|
||||
Suite *s = suite_create ("vorbisenc");
|
||||
TCase *tc_chain = tcase_create ("general");
|
||||
|
||||
suite_add_tcase (s, tc_chain);
|
||||
tcase_add_test (tc_chain, test_granulepos_offset);
|
||||
tcase_add_test (tc_chain, test_timestamps);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int nf;
|
||||
|
||||
Suite *s = vorbisenc_suite ();
|
||||
SRunner *sr = srunner_create (s);
|
||||
|
||||
gst_check_init (&argc, &argv);
|
||||
|
||||
srunner_run_all (sr, CK_NORMAL);
|
||||
nf = srunner_ntests_failed (sr);
|
||||
srunner_free (sr);
|
||||
|
||||
return nf;
|
||||
}
|
Loading…
Reference in a new issue