HLS Demux - Incomplete when master manifest is given

arunz8 arunz at hotmail.com
Wed Aug 28 08:09:44 UTC 2019


Hi,

Using the Gstreamer to get the contents of the given URL as TS packet. When
I give one of the playlist in the master manifest it is working. But when I
provide master manifest as input, it retrieves only the first chunk and then
getting EOS. 

When I tried with a program (just souphttp, hlsdemux and appsink (added
after new pad signal) I see a new pad request again before the application
stops. *What this new pad (after the appsink added) really mean? Output has
first chunk in this case.*

OUTPUT:

~/gst/gst-template/gst-app/src$ gst-app
http://devimages.apple.com.edgekey.net/iphone/samples/bipbop/bipbopall.m3u8
outf1.ts
Pipeline state changed from NULL to READY:
*Received new pad 'src_0' from 'hlsdemux' (0x90ece0:(nil)):*
Link succeeded (type 'video/mpegts').
Pipeline state changed from READY to PAUSED:
Pipeline state changed from PAUSED to PLAYING:
*Received new pad 'src_1' from 'hlsdemux' (0x90fd10:0x90ece0):*
Already linked sink1 type=video/mpegts
End-Of-Stream reached.


I tried with gst-launch and found the same behavior. * Why? and how to fix
this?*

gst-launch-1.0 -v souphttpsrc
location="http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8" !
hlsdemux ! tsdemux ! h264parse ! avdec_h264 ! autovideosink    ----- Stops
after the first chunk

gst-launch-1.0 -v souphttpsrc
location="http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8 
-- Working but with a chosen playlist.


Source code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <gst/gst.h>
#include <gst/app/gstappsink.h>

#define MAX_URL_LEN 150
#define MAX_FILENAME_LEN 100
/* Structure to contain all our information, so we can pass it to callbacks
*/
typedef struct _CustomData
{
    GstElement *pipeline;
    GstElement *httpsrc;
    GstElement *hlsDemux;
    GstElement *filesink;
    GstElement *appsink1;
    char url[MAX_URL_LEN];
    char outFile[MAX_FILENAME_LEN];
    int fHandle;
    GstPad *curr_pad;
} CustomData;


/* Handler for the pad-added signal */
static void pad_added_handler(GstElement *src, GstPad *pad, CustomData
*data);

/* called when the appsink notifies us that there is a new buffer ready for
 * processing */
static GstFlowReturn
on_new_sample_from_sink(GstElement * elt, CustomData * data)
{
    GstSample *sample;
    GstBuffer *app_buffer, *buffer;
    GstFlowReturn ret;
    GstMapInfo map;

    /* get the sample from appsink */
    sample = gst_app_sink_pull_sample(GST_APP_SINK(elt));
    buffer = gst_sample_get_buffer(sample);
    gst_buffer_map(buffer, &map, GST_MAP_READ);
    
    write(data->fHandle, map.data, map.size);

    /* we don't need the appsink sample anymore */
    gst_sample_unref(sample);

    return ret;
}

int main(int argc, char *argv[])
{
    CustomData data;
    GstBus *bus;
    GstMessage *msg;
    GstStateChangeReturn ret;
    gboolean terminate = FALSE;

    if (argc < 3)
    {
        g_printerr("Usage: %s url outfile\n", argv[0]);
        return -1;
    }

    strcpy(data.url, argv[1]);
    strcpy(data.outFile, argv[2]);
    // open output file. 
    data.fHandle = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC,
        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

    if (data.fHandle < 0)
    {
        g_printerr("Could not open file '%s'\n", argv[2]);
        return -1;;
    }

    /* Initialize GStreamer */
    gst_init(&argc, &argv);

    /* Create the elements */
    data.httpsrc = gst_element_factory_make("souphttpsrc", "source");
    data.hlsDemux = gst_element_factory_make("hlsdemux", "hlsdemux");
    data.appsink1 = gst_element_factory_make("appsink", "appsink1");

    /* Create the empty pipeline */
    data.pipeline = gst_pipeline_new("test-pipeline");

    if (!data.pipeline || !data.httpsrc || !data.hlsDemux || !data.appsink1
)
    {
        g_printerr("Not all elements could be created.\n");
        return -1;
    }

    /* Build the pipeline. Note that we are NOT linking the appsink at this
     * point. We will do it later. */
    gst_bin_add_many(GST_BIN(data.pipeline), data.httpsrc, data.hlsDemux,
data.appsink1,  NULL);
    if (!gst_element_link(data.httpsrc, data.hlsDemux))
    {
        g_printerr("element link failed\n");
        gst_object_unref(data.pipeline);
        return -1;
    }


    /* Modify the source's properties */

    /* Set the URI to play */
 //   g_object_set(data.httpsrc, "location",
"http://devimages.apple.com/iphone/samples/bipbop/gear4/prog_index.m3u8",
NULL);
    g_object_set(data.httpsrc, "location", data.url, NULL);
    /* Set properties of appsink*/
    g_object_set(data.appsink1, "emit-signals", TRUE, "sync", TRUE, NULL);
    g_signal_connect(data.appsink1, "new-sample",
        G_CALLBACK(on_new_sample_from_sink), &data);



    /* Connect to the pad-added signal */
    g_signal_connect(data.hlsDemux, "pad-added",
G_CALLBACK(pad_added_handler), &data);
    /* Start playing */
    ret = gst_element_set_state(data.pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE)
    {
        g_printerr("Unable to set the pipeline to the playing state.\n");
        gst_object_unref(data.pipeline);
        return -1;
    }

    /* Listen to the bus */
    bus = gst_element_get_bus(data.pipeline);
    do
    {
        msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
            GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR |
GST_MESSAGE_EOS);

        /* Parse message */
        if (msg != NULL)
        {
            GError *err;
            gchar *debug_info;

            switch (GST_MESSAGE_TYPE(msg))
            {
            case GST_MESSAGE_ERROR:
                gst_message_parse_error(msg, &err, &debug_info);
                g_printerr("Error received from element %s: %s\n",
GST_OBJECT_NAME(msg->src), err->message);
                g_printerr("Debugging information: %s\n", debug_info ?
debug_info : "none");
                g_clear_error(&err);
                g_free(debug_info);
                terminate = TRUE;
                break;
            case GST_MESSAGE_EOS:
                g_print("End-Of-Stream reached.\n");
                terminate = TRUE;
                break;
            case GST_MESSAGE_STATE_CHANGED:
                /* We are only interested in state-changed messages from the
pipeline */
                if (GST_MESSAGE_SRC(msg) == GST_OBJECT(data.pipeline))
                {
                    GstState old_state, new_state, pending_state;
                    gst_message_parse_state_changed(msg, &old_state,
&new_state, &pending_state);
                    g_print("Pipeline state changed from %s to %s:\n",
                        gst_element_state_get_name(old_state),
gst_element_state_get_name(new_state));
                }
                break;
            default:
                /* We should not reach here */
                g_printerr("Unexpected message received.\n");
                break;
            }
            gst_message_unref(msg);
        }
    } while (!terminate);

    /* Free resources */
    gst_object_unref(bus);
    gst_element_set_state(data.pipeline, GST_STATE_NULL);
    gst_object_unref(data.pipeline);
    close(data.fHandle);
    return 0;
}


/* This function will be called by the pad-added signal */
static void pad_added_handler(GstElement *src, GstPad *new_pad, CustomData
*data)
{
    GstPad *sink_pad = gst_element_get_static_pad(data->appsink1, "sink");
    GstPadLinkReturn ret;
    GstCaps *new_pad_caps = NULL;
    GstStructure *new_pad_struct = NULL;
    const gchar *new_pad_type = NULL;

    g_print("Received new pad '%s' from '%s' (%p:%p):\n",
GST_PAD_NAME(new_pad), GST_ELEMENT_NAME(src), new_pad, data->curr_pad);

    /* Check the new pad's type */
    new_pad_caps = gst_pad_get_current_caps(new_pad);
    new_pad_struct = gst_caps_get_structure(new_pad_caps, 0);
    new_pad_type = gst_structure_get_name(new_pad_struct);

    /* If our converter is already linked, we have nothing to do here */
    if (gst_pad_is_linked(sink_pad))
    {
        g_print("Already linked sink1 type=%s\n", new_pad_type);
        goto exit;
    }

    if (!sink_pad)
    {
        g_print("couldnt get appsink pad\n");
        goto exit;

    }

    /* Attempt the link */
    ret = gst_pad_link(new_pad, sink_pad);
    if (GST_PAD_LINK_FAILED(ret))
    {
        g_print("Type is '%s' but link failed.\n", new_pad_type);
    }
    else
    {
        g_print("Link succeeded (type '%s').\n", new_pad_type);
        data->curr_pad = new_pad;
    }

exit:
    /* Unreference the new pad's caps, if we got them */
    if (new_pad_caps != NULL)
        gst_caps_unref(new_pad_caps);

    /* Unreference the sink pad */
    gst_object_unref(sink_pad);
}


Thanks




--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/


More information about the gstreamer-devel mailing list