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