How to use tsparse to extract an non PES stream

Randy Li randy.li at synaptics.com
Tue Jul 6 10:31:40 UTC 2021



On 7/6/21 6:21 PM, Edward Hervey wrote:
> CAUTION: Email originated externally, do not click links or open attachments unless you recognize the sender and know the content is safe.
> 
> 
> Hi,
> 
>    Please file an issue here :
> https://urldefense.proofpoint.com/v2/url?u=https-3A__gitlab.freedesktop.org_gstreamer_gst-2Dplugins-2Dbad_&d=DwIDaQ&c=7dfBJ8cXbWjhc0BhImu8wQ&r=P4xb2_7biqBxD4LGGPrSV6j-jf3C3xlR7PXU-mLTeZE&m=M3wWjbeZvcDaHO3yO3o_PZ0n8v2ISLGCKKyeF7QPmf4&s=g9ZVXvg1r1e18E_JLqj3DhD-JMmpzBf8uQ1QgxRCiL8&e=
> 
>    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>

I can't upload that file now but I just used the ts2es utility from 
tstools, I could know it is just a raw ES stream(in AVC Annex B) packet 
into MPEG-TS packets.
Besides that program(stream) is not in PMT of that file, it has audio 
and video streams in the PMT and packed into PES packets, which would 
work normal.

I could open a new issue in -bad but it seems not that complex as I 
thought before. But I think this problem could be resolved more easy if 
I know a method to extract an specially pid stream from the MPEG-TS 
stream. Likes

tsparse pid=4112 ! h264parse ! decodebin ! autovideosink

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

-- 
Hsia-Jun(Randy) Li


More information about the gstreamer-devel mailing list