2 * WebRTC Internal Tooling - Looping V4L2 player
3 * Author: Patrik Höglund (phoglund@webrtc.org)
5 * This file implements a basic raw video file player which loops its input
6 * file indefinitely. It is intended to be used with the v4l2loopback driver in
7 * order to play the contents of a file as if it were a webcam. Therefore, this
8 * program will write to a v4l2loopback device, say /dev/video1, and the driver
9 * will then reflect the data unmodified to any reading processes.
11 * This program basically does the same thing as
12 * gst-launch-0.10 -v filesrc location=resources/foreman_cif.yuv ! \
13 * videoparse width=352 height=288 ! v4l2sink device=/dev/video1
15 * , but with looping. Looping is unfortunately impossible to do with a regular
16 * gstreamer pipeline, hence the existence of this program.
18 * It can be run something like this:
19 * v4l2_file_player foreman_cif_short.yuv 352 288 /dev/video1 >& /dev/null
21 * The program might print warnings about failed ioctls (for instance for
22 * VIDIOC_G_FMT), but that doesn't seem to be a problem.
24 * To test, you can run for instance mplayer tv:// -tv device=/dev/video1 and
25 * verify that you see your video playing repeatedly.
27 * This code is based off the hello world example in the gstreamer manual.
28 * You can find the original code in chapter 10, "Your First Application":
29 * http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/
38 } main_loop_and_pipeline_t
;
40 static gboolean
bus_call(GstBus
*bus
, GstMessage
*msg
, gpointer data
) {
41 main_loop_and_pipeline_t
*main_loop_and_pipeline
=
42 (main_loop_and_pipeline_t
*)data
;
44 GMainLoop
*loop
= main_loop_and_pipeline
->main_loop
;
45 GstElement
*pipeline
= main_loop_and_pipeline
->pipeline
;
47 switch (GST_MESSAGE_TYPE (msg
)) {
49 /* Reached end of input video - restart */
50 gst_element_set_state(pipeline
, GST_STATE_READY
);
51 gst_element_set_state(pipeline
, GST_STATE_PLAYING
);
54 case GST_MESSAGE_ERROR
: {
58 gst_message_parse_error(msg
, &error
, &debug
);
61 g_printerr("Error: %s\n", error
->message
);
64 g_main_loop_quit(loop
);
74 int main(int argc
, char *argv
[]) {
75 gst_init(&argc
, &argv
);
77 GMainLoop
*main_loop
= g_main_loop_new(NULL
, FALSE
);
79 /* Check input arguments */
80 if (argc
!= 5 || atoi(argv
[2]) == 0 || atoi(argv
[3]) == 0) {
81 g_printerr("Usage: %s <filename> <width> <height> <device>\n\n", argv
[0]);
82 g_printerr("Arguments:\n");
83 g_printerr(" filename: Path to the video file.\n");
84 g_printerr(" width: Video width.\n");
85 g_printerr(" height: Video height.\n");
86 g_printerr(" device: Device to write to (like /dev/video1).\n");
90 /* Create gstreamer pipeline elements. */
91 GstElement
*pipeline
= gst_pipeline_new("looping-video-player");
92 GstElement
*source
= gst_element_factory_make("filesrc", "file-source");
93 GstElement
*parse
= gst_element_factory_make("videoparse", "video-parse");
94 GstElement
*v4l2_sink
= gst_element_factory_make("v4l2sink", "v4l2-sink");
96 if (!pipeline
|| !source
|| !parse
|| !v4l2_sink
) {
97 g_printerr("One GST element could not be created. Exiting.\n");
101 /* Set up input parameters. */
102 g_object_set(G_OBJECT (source
), "location", argv
[1], NULL
);
103 g_object_set(G_OBJECT (parse
), "width", atoi(argv
[2]), NULL
);
104 g_object_set(G_OBJECT (parse
), "height", atoi(argv
[3]), NULL
);
105 g_object_set(G_OBJECT (v4l2_sink
), "device", argv
[4], NULL
);
107 /* Add a callback to we can react to end-of-stream and errors. */
108 main_loop_and_pipeline_t main_loop_and_pipeline
;
109 main_loop_and_pipeline
.main_loop
= main_loop
;
110 main_loop_and_pipeline
.pipeline
= pipeline
;
112 GstBus
*bus
= gst_pipeline_get_bus(GST_PIPELINE (pipeline
));
113 gst_bus_add_watch(bus
, bus_call
, &main_loop_and_pipeline
);
114 gst_object_unref(bus
);
116 /* Assemble the pipeline. */
117 gst_bin_add_many(GST_BIN (pipeline
), source
, parse
, v4l2_sink
, NULL
);
118 gst_element_link(source
, parse
);
119 gst_element_link(parse
, v4l2_sink
);
122 gst_element_set_state(pipeline
, GST_STATE_PLAYING
);
123 g_main_loop_run(main_loop
);