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