1 module dcv.example.video;
2 
3 /** 
4  * Video streaming example using dcv library.
5  */
6 
7 import std.stdio;
8 import std.datetime : StopWatch;
9 import core.stdc.stdlib;
10 
11 import dcv.io.image;
12 import dcv.imgproc.color;
13 import dcv.core.utils;
14 import dcv.io.video;
15 import dcv.plot.figure;
16 
17 void main(string[] args)
18 {
19     if (args.length == 2 && args[1] == "-h")
20     {
21         printHelp();
22         return;
23     }
24 
25     //////////// Open the video stream ////////////////
26 
27     InputStream inStream = new InputStream;
28 
29     string path; // path to the video
30     InputStreamType type; // type of the stream (file or live)
31 
32     if (!parseArgs(args, path, type))
33     {
34         writeln("Error occurred while parsing arguments.\n\n");
35         printHelp();
36         return;
37     }
38 
39     try
40     {
41         // Open the example video
42         inStream.open(path, type);
43     }
44     catch
45     {
46         writeln("Cannot open input video stream");
47         exit(-1);
48     }
49 
50     // Check if video has been opened correctly
51     if (!inStream.isOpen)
52     {
53         writeln("Cannot open input video stream");
54         exit(-1);
55     }
56 
57     //////////// Read video frames //////////////////
58 
59     Image frame; // frame image buffer, where each next frame of the video is stored.
60 
61     // read the frame rate, if info is available.
62     double fps = inStream.frameRate ? inStream.frameRate : 30.0;
63     // calculate frame wait time in miliseconds - if video is live, set to minimal value.
64     double waitFrame = (type == InputStreamType.LIVE) ? 1.0 : 1000.0 / fps;
65 
66     StopWatch s;
67     s.start;
68 
69     // Read each next frame of the video in the loop.
70     while (inStream.readFrame(frame))
71     {
72         import std.algorithm.comparison : max;
73 
74         s.reset;
75 
76         // If video frame pixel format is YUV, convert the data to RGB, then show it on screen
77         if (frame.format == ImageFormat.IF_YUV)
78             frame.sliced.yuv2rgb!ubyte.imshow(path);
79         else
80             frame.imshow(path);
81 
82         // Compensate fps wait for lost time on color conversion.
83         int wait = max(1, cast(int)waitFrame - cast(int)s.peek.msecs);
84 
85         // If user presses escape key, stop the streaming.
86         if (waitKey(wait) == KEY_ESCAPE)
87             break;
88 
89         /*
90         Ask if figure with given name is visible.
91 
92         Normally, you can close the figure window by pressing the 'x' button.
93         That way, figure closes, and visible property will return false.
94         So, if user presses the 'x' button, normal behavior would be to break the 
95         streaming loop.
96         */
97         if (!figure(path).visible)
98             break;
99     }
100 
101 }
102 
103 void printHelp()
104 {
105     writeln(`
106 DCV Video Streaming Example.
107 
108 Run example program without arguments, to load and show the example video file centaur_1.mpg.
109 
110 If multiple parameters are given, then parameters are considered to be:
111 
112 1 - video stream mode (-f for file, -l for webcam or live mode);
113 2 - video stream name (for file mode it is the path to the file, for webcam it is the name of the stream, e.g. /dev/video0);
114 
115 Examples:
116 ./video -l /dev/video0
117 ./video -f ../data/centaur_1.mpg
118 
119 Tip:
120 To run the example program in best performance, compile with one of the following configurations
121 dub build --compiler=ldc2 --build=release
122 dub build --compiler=dmd --build=release-nobounds
123 `);
124 }
125 
126 bool parseArgs(in string[] args, out string path, out InputStreamType type)
127 {
128     if (args.length == 1)
129         return true;
130     else if (args.length != 3)
131         return false;
132 
133     type = InputStreamType.FILE;
134 
135     switch (args[1])
136     {
137     case "-file":
138     case "-f":
139         type = InputStreamType.FILE;
140         break;
141     case "-live":
142     case "-l":
143         type = InputStreamType.LIVE;
144         break;
145     default:
146         writeln("Invalid input type argument: ", args[2]);
147         exit(-1);
148     }
149 
150     path = args[2];
151 
152     return true;
153 }