/**
 * hls_progress_buffer_chain()
 *
 * Primary function for push-mode.  Receives data from hls progressbuffer's sink pad.
 */
static GstFlowReturn hls_progress_buffer_chain(GstPad *pad, GstBuffer *data)
{
    HLSProgressBuffer *element = HLS_PROGRESS_BUFFER(GST_PAD_PARENT(pad));
    GstFlowReturn  result = GST_FLOW_OK;

    if (element->is_flushing || element->is_eos)
    {
        // INLINE - gst_buffer_unref()
        gst_buffer_unref(data);
        return GST_FLOW_WRONG_STATE;
    }

    g_mutex_lock(element->lock);
    cache_write_buffer(element->cache[element->cache_write_index], data);
    g_cond_signal(element->add_cond);
    g_mutex_unlock(element->lock);

    // INLINE - gst_buffer_unref()
    gst_buffer_unref(data);

    return result;
}
Example #2
0
/**
 * progress_buffer_enqueue_item()
 *
 * Add an item in the queue. Must be called in the locked context.  Item may be event or data.
 */
static GstFlowReturn progress_buffer_enqueue_item(ProgressBuffer *element, GstMiniObject *item)
{
    gboolean signal = FALSE;

    if (GST_IS_BUFFER (item))
    {
        gdouble elapsed;
        // update sink segment position
        element->sink_segment.position = GST_BUFFER_OFFSET(GST_BUFFER(item)) + gst_buffer_get_size (GST_BUFFER(item));

        if(element->sink_segment.stop < element->sink_segment.position) // This must never happen.
            return  GST_FLOW_ERROR;

        cache_write_buffer(element->cache, GST_BUFFER(item));

        elapsed = g_timer_elapsed(element->bandwidth_timer, NULL);
        element->subtotal += gst_buffer_get_size (GST_BUFFER(item));

        if (elapsed > 1.0)
        {
            element->bandwidth = element->subtotal/elapsed;
            element->subtotal = 0;
            g_timer_start(element->bandwidth_timer);
        }

        // send buffer progress position up (used to track buffer fill, etc.)
        signal = send_position_message(element, signal);
    }
    else if (GST_IS_EVENT (item))
    {
        GstEvent *event = GST_EVENT_CAST (item);

        switch (GST_EVENT_TYPE (event))
        {
            case GST_EVENT_EOS:
                element->eos_status.eos = TRUE;
                if (element->sink_segment.position < element->sink_segment.stop)
                    element->sink_segment.stop = element->sink_segment.position;

                progress_buffer_set_pending_event(element, NULL);

                signal = send_position_message(element, TRUE);
                gst_event_unref(event); // INLINE - gst_event_unref()
                break;

            case GST_EVENT_SEGMENT:
            {
                GstSegment segment;

                element->unexpected = FALSE;

                gst_event_copy_segment (event, &segment);

                if (segment.format != GST_FORMAT_BYTES)
                {
                    gst_element_message_full(GST_ELEMENT(element), GST_MESSAGE_ERROR, GST_STREAM_ERROR, GST_STREAM_ERROR_FORMAT,
                                             g_strdup("GST_FORMAT_BYTES buffers expected."), NULL,
                                             ("progressbuffer.c"), ("progress_buffer_enqueue_item"), 0);
                    gst_event_unref(event); // INLINE - gst_event_unref()
                    return GST_FLOW_ERROR;
                 }

                if (segment.stop - segment.start <= 0)
                {
                    gst_element_message_full(GST_ELEMENT(element), GST_MESSAGE_ERROR, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
                                             g_strdup("Only limited content is supported by progressbuffer."), NULL,
                                             ("progressbuffer.c"), ("progress_buffer_enqueue_item"), 0);
                    gst_event_unref(event); // INLINE - gst_event_unref()
                    return GST_FLOW_ERROR;
                }

                if ((segment.flags & GST_SEGMENT_FLAG_UPDATE) == GST_SEGMENT_FLAG_UPDATE) // Updating segments create new cache.
                {
                    if (element->cache)
                        destroy_cache(element->cache);

                    element->cache = create_cache();
                    if (!element->cache)
                    {
                        gst_element_message_full(GST_ELEMENT(element), GST_MESSAGE_ERROR, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_OPEN_READ_WRITE,
                                                 g_strdup("Couldn't create backing cache"), NULL,
                                                 ("progressbuffer.c"), ("progress_buffer_enqueue_item"), 0);
                        gst_event_unref(event); // INLINE - gst_event_unref()
                        return GST_FLOW_ERROR;
                    }
                }
                else
                {
                    cache_set_write_position(element->cache, 0);
                    cache_set_read_position(element->cache, 0);
                    element->cache_read_offset = segment.start;
                }

                gst_segment_copy_into (&segment, &element->sink_segment);
                progress_buffer_set_pending_event(element, event);
                element->instant_seek = TRUE;

                signal = send_position_message(element, TRUE);
                break;
            }

            default:
                gst_event_unref(event); // INLINE - gst_event_unref()
                break;
        }
    }

    if (signal)
        g_cond_signal(&element->add_cond);

    return GST_FLOW_OK;
}