How to use tsparse to extract an non PES stream

Randy Li randy.li at synaptics.com
Tue Jul 6 09:44:10 UTC 2021


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);

}

-- 
Randy Li


More information about the gstreamer-devel mailing list