GST_DEBUG_CATEGORY (sirenenc_debug);
#define GST_CAT_DEFAULT (sirenenc_debug)
+#define FRAME_DURATION (20 * GST_MSECOND)
+
/* elementfactory information */
static const GstElementDetails gst_siren_enc_details =
GST_ELEMENT_DETAILS ("Siren Encoder element",
{
GstSirenEnc *enc = GST_SIREN_ENC (gst_pad_get_parent_element (pad));
GstFlowReturn ret = GST_FLOW_OK;
- GstBuffer *encoded = NULL;
- guint8 *data = NULL;
- gint out_offset = 0;
- gint encode_ret = 0;
- gint size = 0;
- guint in_offset = 0;
-
- GST_OBJECT_LOCK (enc);
+ GstBuffer *out_buf;
+ guint8 *in_data, *out_data;
+ guint8 *to_free = NULL;
+ guint i, size, num_frames;
+ gint out_size, in_size;
+ gint encode_ret;
+ gboolean discont;
+ GstClockTime timestamp;
+ guint64 distance;
+
+ discont = GST_BUFFER_IS_DISCONT (buf);
+ if (discont) {
+ GST_DEBUG_OBJECT (enc, "received DISCONT, flush adapter");
+ gst_adapter_clear (enc->adapter);
+ enc->discont = TRUE;
+ }
gst_adapter_push (enc->adapter, buf);
GST_BUFFER_SIZE (buf), gst_adapter_available (enc->adapter));
size = gst_adapter_available (enc->adapter);
- size /= 16;
- size -= size % 40;
- if (size == 0) {
- GST_OBJECT_UNLOCK (enc);
- goto out;
- }
+ /* we need to process 640 input bytes to produce 40 output bytes */
+ /* calculate the amount of frames we will handle */
+ num_frames = size / 640;
- data = gst_adapter_take (enc->adapter, size * 16);
+ /* no frames, wait some more */
+ if (num_frames == 0)
+ goto done;
- GST_OBJECT_UNLOCK (enc);
+ /* this is the output size */
+ in_size = num_frames * 640;
+ out_size = num_frames * 40;
- ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
- GST_BUFFER_OFFSET (buf) / 16, size, enc->srccaps, &encoded);
+ GST_LOG_OBJECT (enc, "we have %u frames, %u in, %u out", num_frames, in_size,
+ out_size);
+ /* get a buffer */
+ ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad, -1,
+ out_size, enc->srccaps, &out_buf);
if (ret != GST_FLOW_OK)
- goto out;
-
- while (out_offset < size && ret == GST_FLOW_OK) {
- GST_LOG_OBJECT (enc, "Encoding frame");
-
- encode_ret = Siren7_EncodeFrame (enc->encoder,
- data + in_offset, GST_BUFFER_DATA (encoded) + out_offset);
- if (encode_ret != 0) {
- GST_ERROR_OBJECT (enc, "Siren7_EncodeFrame returned %d", encode_ret);
- ret = GST_FLOW_ERROR;
- gst_buffer_unref (encoded);
- goto out;
- }
-
- out_offset += 40;
- in_offset += 640;
+ goto alloc_failed;
+
+ /* get the timestamp for the output buffer */
+ timestamp = gst_adapter_prev_timestamp (enc->adapter, &distance);
+
+ /* add the amount of time taken by the distance */
+ timestamp += gst_util_uint64_scale_int (distance / 2, GST_SECOND, 16000);
+
+ GST_LOG_OBJECT (enc,
+ "timestamp %" GST_TIME_FORMAT ", distance %" G_GUINT64_FORMAT,
+ GST_TIME_ARGS (timestamp), distance);
+
+ /* get the input data for all the frames */
+ to_free = in_data = gst_adapter_take (enc->adapter, in_size);
+ out_data = GST_BUFFER_DATA (out_buf);
+
+ for (i = 0; i < num_frames; i++) {
+ GST_LOG_OBJECT (enc, "Encoding frame %u/%u", i, num_frames);
+
+ /* encode 640 input bytes to 40 output bytes */
+ encode_ret = Siren7_EncodeFrame (enc->encoder, in_data, out_data);
+ if (encode_ret != 0)
+ goto encode_error;
+
+ /* move to next frame */
+ out_data += 40;
+ in_data += 640;
}
- GST_LOG_OBJECT (enc, "Finished encoding : %d", out_offset);
+ GST_LOG_OBJECT (enc, "Finished encoding");
+
+ /* mark discont */
+ if (enc->discont) {
+ GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DISCONT);
+ enc->discont = FALSE;
+ }
+ GST_BUFFER_TIMESTAMP (out_buf) = timestamp;
+ GST_BUFFER_DURATION (out_buf) = num_frames * FRAME_DURATION;
- ret = gst_pad_push (enc->srcpad, encoded);
+ ret = gst_pad_push (enc->srcpad, out_buf);
-out:
- if (data)
- g_free (data);
+done:
+ if (to_free)
+ g_free (to_free);
gst_object_unref (enc);
+
return ret;
+
+ /* ERRORS */
+alloc_failed:
+ {
+ GST_DEBUG_OBJECT (enc, "failed to pad_alloc buffer: %d (%d)", ret,
+ gst_flow_get_name (ret));
+ goto done;
+ }
+encode_error:
+ {
+ GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
+ ("Error encoding frame: %d", encode_ret));
+ ret = GST_FLOW_ERROR;
+ gst_buffer_unref (out_buf);
+ goto done;
+ }
}
static GstStateChangeReturn
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstSirenEnc *enc = GST_SIREN_ENC (element);
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ enc->discont = FALSE;
+ break;
+ default:
+ break;
+ }
- if (ret == GST_STATE_CHANGE_FAILURE)
- return ret;
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
- GST_OBJECT_LOCK (element);
gst_adapter_clear (enc->adapter);
- GST_OBJECT_UNLOCK (element);
break;
default:
break;