How to use tsparse to extract an non PES stream

Edward Hervey bilboed at bilboed.com
Tue Jul 6 10:21:18 UTC 2021


Hi,

  Please file an issue here :
https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/

  Provide a link to the file in that issue, or else the output of
GST_DEBUG=2,*ts*:8 GST_DEBUG_FILE=/location/to/logfile gst-play-1.0 <yourfile>

  BR,

     Edward

On Tue, 2021-07-06 at 17:44 +0800, Randy Li via gstreamer-devel wrote:
> Hello
> 
> I am debugging a MPEG-TS demux, there is a video file that VLC could 
> play but neither FFMpeg nor Gstreamer could. I found out the target 
> video channel(program) seems not to be packed into the PES packet, I 
> want to extract it out first.
> 
> I think the tsparse should be the plugin I could use for it, then I
> wrote a demo likes below, but it doesn't work at all. Anything went 
> wrong here or I should write a plugin myself ?
> 
> 
> #define _GNU_SOURCE             /* See feature_test_macros(7) */
> #include <unistd.h>
> #include <stdio.h>
> #include <stdbool.h>
> #include <fcntl.h>
> #include <sys/wait.h>
> #include <sys/file.h>
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <string.h>
> #include <gst/gst.h>
> #include <gst/check/gstcheck.h>
> 
> static GMainLoop *loop;
> 
> typedef struct {
>      GstElement *pipeline;
>      GstBus *bus;
>      guint target_prog;
> } DemoApp;
> 
> /* the master process'es async GstBus callback */
> static gboolean
> bus_handler (GstBus * bus, GstMessage * message, gpointer user_data)
> {
>    DemoApp *d = user_data;
> 
>    switch (GST_MESSAGE_TYPE (message)) {
>      case GST_MESSAGE_ERROR:{
>        GError *err;
>        gchar *dbg;
> 
>        /* elements we are removing might error out as they are taken out
>           of the pipeline, and fail to push. We don't care about those. */
> 
>        gst_message_parse_error (message, &err, &dbg);
>        g_printerr ("ERROR: %s\n", err->message);
>        if (dbg != NULL)
>          g_printerr ("ERROR debug information: %s\n", dbg);
>        g_error_free (err);
>        g_free (dbg);
>        g_assert_not_reached ();
>        break;
>      }
>      case GST_MESSAGE_WARNING:{
>        GError *err;
>        gchar *dbg;
> 
>        gst_message_parse_warning (message, &err, &dbg);
>        g_printerr ("WARNING: %s\n", err->message);
>        if (dbg != NULL)
>          g_printerr ("WARNING debug information: %s\n", dbg);
>        g_error_free (err);
>        g_free (dbg);
>        g_assert_not_reached ();
>        break;
>      }
>      case GST_MESSAGE_EOS:
>        g_main_loop_quit (loop);
>        break;
>      default:
>        break;
>    }
>    return TRUE;
> }
> 
> /* source construction functions */
> static bool
> add_program_pad(DemoApp *d, GstElement *element)
> {
>    GstBin *pipeline = d->pipeline;
>    GstElement *next = NULL;
>    GstPad *pad = NULL;
>    GstPad *sink_pad = NULL;
>    gchar targetpad[20];
>    GstPadLinkReturn ret;
> 
>    g_snprintf(targetpad, sizeof(targetpad), "program_%u",
>               d->target_prog);
>    pad = gst_element_get_request_pad(element, targetpad);
>    if (!pad) {
>        g_printerr("can't request program pad\n");
>        return false;
>    }
> 
>    next = gst_bin_get_by_name (GST_BIN (pipeline), "vqueue");
> 
>    sink_pad = gst_element_get_static_pad (next, "sink");
>    ret = gst_pad_link (pad, sink_pad);
>    if (ret != GST_PAD_LINK_OK)
>    {
>        g_assert_not_reached();
>    }
>    gst_object_unref (sink_pad);
> 
>    gst_object_unref (next);
> 
>    return true;
> }
> 
> bool
> create_mpegts_source (DemoApp *d, const char *loc)
> {
>    GstElement *pipeline, *filesrc, *fakesink, *tsparse,
>               *vqueue, *filesink;
> 
>    pipeline = gst_pipeline_new ("tsextract");
>    d->pipeline = pipeline;
> 
>    filesrc = gst_element_factory_make ("filesrc", NULL);
>    g_object_set (filesrc, "location", loc, NULL);
>    tsparse = gst_element_factory_make ("tsparse", NULL);
>    //fakesink = gst_element_factory_make ("fakesink", NULL);
>    vqueue = gst_element_factory_make ("queue", "vqueue");
>    filesink = gst_element_factory_make ("filesink", "sink");
>    g_object_set (filesink, "location", "./tsout", NULL);
> 
>    gst_bin_add_many (GST_BIN (pipeline), filesrc, tsparse,
>        vqueue, filesink, NULL);
>    gst_element_link_many (filesrc, tsparse, NULL);
>    gst_element_link_many (vqueue, filesink, NULL);
> 
>    add_program_pad(d, tsparse);
> 
>    d->bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
>    gst_bus_add_watch (d->bus, bus_handler, d);
> 
>    return true;
> }
> 
> int
> main (int argc, char **argv)
> {
>    DemoApp *d = NULL;
>    GOptionContext *context;
>    GError *error = NULL;
>    gchar *uri = NULL;
>    gchar *path = NULL;
>    gint program_id = 0;
> 
>    GOptionEntry entries[] = {
>      {"uri", '\0', 0, G_OPTION_ARG_STRING, &uri, "video source URI", NULL},
>      {"path", 'i', 0, G_OPTION_ARG_STRING, &path,
>          "the path of a video file or directory", NULL},
>      {"program", 'p', 0, G_OPTION_ARG_INT, &program_id,
>          "MPEG-TS program id", NULL},
>      {NULL}
>    };
> 
>    gst_init (&argc, &argv);
> 
>    context = g_option_context_new ("MPEG-TS Extractor");
>    g_option_context_add_main_entries (context, entries, NULL);
>    if (!g_option_context_parse (context, &argc, &argv, &error)) {
>      g_printerr ("option parsing failed: %s\n", error->message);
>      return 1;
>    }
>    g_option_context_free (context);
> 
>    if (!uri && !path) {
>      g_printerr ("need input file\n", argv[0]);
>      return 1;
>    }
> 
>    if (!program_id) {
>      g_printerr ("program id\n", argv[0]);
>      return 1;
>    }
> 
>    d = g_slice_new0 (DemoApp);
>    d->target_prog = program_id;
> 
>    create_mpegts_source(d, path);
>    gst_element_set_state (d->pipeline, GST_STATE_PLAYING);
> 
>    loop = g_main_loop_new (NULL, FALSE);
>    g_main_loop_run (loop);
> 
>    gst_element_set_state (d->pipeline, GST_STATE_NULL);
>    gst_object_unref (d->pipeline);
> 
>    g_slice_free (DemoApp, d);
> 
> }
> 




More information about the gstreamer-devel mailing list