Fix command line handling
[videoplayer.git] / main.cpp
blob850c28368c2db017480afc91c6c1cdc31987b4e6
1 /* ***** BEGIN LICENSE BLOCK *****
3 * The MIT License
5 * Copyright (c) 2008 BBC Research
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
25 * ***** END LICENSE BLOCK ***** */
27 #include "mainwindow.h"
29 #ifdef Q_OS_LINUX
30 #include "X11/Xlib.h"
31 #endif
33 #include <QApplication>
35 #include <string>
36 using namespace std;
38 #include <iostream>
39 #include <boost/program_options.hpp>
40 namespace po = boost::program_options;
42 #include "readerInterface.h"
43 #include "yuvReader.h"
44 #ifdef HAVE_DIRAC
45 #include "diracReader.h"
46 #endif
48 #include "frameQueue.h"
49 #include "videoTransport.h"
50 #ifdef Q_OS_LINUX
51 #include "QShuttlePro.h"
52 #endif
54 #ifdef Q_OS_UNIX
55 #include "QConsoleInput.h"
56 #endif
58 #include "GLvideo_params.h"
60 #include "config.h"
62 struct Transport_params {
63 bool looping;
64 QString fileName;
65 QString fileType;
66 bool quit_at_end;
67 bool forceFileType;
68 int videoWidth;
69 int videoHeight;
72 void
73 usage()
75 printf("\nOpenGL accelerated YUV video player.");
76 printf("\n");
77 printf("\nUsage: progname -<flag1> [<flag1_val>] ... <input>");
78 printf("\n");
79 printf("\nSupported file formats:");
80 printf("\n");
81 printf("\n .i420 4:2:0 YUV 8 bit planar");
82 printf("\n .yv12 4:2:0 YVU 8 bit planar");
83 printf("\n .420p 4:2:0 YUV 8 bit planar");
84 printf("\n .422p 4:2:2 YUV 8 bit planar");
85 printf("\n .444p 4:4:4 YUV 8 bit planar");
86 printf("\n .uyvy 4:2:2 YUV 8 bit packed");
87 printf("\n .v210 4:2:2 YUV 10 bit packed");
88 printf("\n .v216 4:2:2 YUV 16 bit packed");
89 printf("\n .16p0 4:2:0 YUV 16 bit planar");
90 printf("\n .16p2 4:2:2 YUV 16 bit planar");
91 printf("\n .16p4 4:4:4 YUV 16 bit planar");
92 printf("\n");
94 printf("\nKeypress Action");
95 printf("\n======== ======");
96 printf("\no Toggle OSD state");
97 printf("\nf Toggle full screen mode");
98 printf("\nm Switch to output levels from user flags out-range and out-black");
99 printf("\nn Switch to video output levels, out-range=240 out-black=16");
100 printf("\nb Switch to computer output levels, out-range=256, out-black=0");
101 printf("\nEsc Return from full screen mode to windowed");
102 printf("\na Toggle aspect ratio lock");
103 printf("\nd Toggle deinterlacing of an interlaced source");
104 printf("\nSpace Play/Pause");
105 printf("\ns Stop");
106 printf("\n1,2,3,4,5,6,7 Play forward at 1,2,5,10,20,50,100x");
107 printf("\nCTRL + 1,2,3,4,5,6,7 Play backward at 1,2,5,10,20,50,100x");
108 printf("\n> Jog one frame forward when paused");
109 printf("\n< Jog one frame backward when paused");
110 printf("\ny Toggle display of luma on/off");
111 printf("\nc Toggle display of chroma on/off");
112 printf("\nh Switch to HDTV colour matrix kr=0.2126 kg=0.7152 kb=0.0722");
113 printf("\nj Switch to SDTV colour matrix kr=0.2990 kg=0.5870 kb=0.1140");
114 printf("\nk Switch to colour matrix kr, kg, kb from user flags");
115 printf("\nq Quit");
116 printf("\n");
117 printf("\n");
120 bool
121 parseCommandLine(int argc, char **argv, GLvideo_params& vp, Transport_params& tp, Qt_params& qt)
123 bool allParsed = true; //default to command line parsing succeeding
124 int cols = 81;
126 if (getenv("COLUMNS"))
127 cols = atoi(getenv("COLUMNS"));
129 try {
130 // Declare the supported options.
131 po::options_description desc("Allowed options type default description\n"
132 "=============== ==== ======= ===========", cols);
133 desc.add_options()
134 ("width,w", po::value(&tp.videoWidth), "int 1920 Width of video luma component")
135 ("height,h", po::value(&tp.videoHeight), "int 1080 Height of video luma component")
136 ("repeats,r", po::value(&vp.frame_repeats), "int 0 Frame is repeated r extra times")
137 ("loop,l", po::value(&tp.looping), "int 1 Number of times to loop video (1=inf)")
138 ("quit,q", po::bool_switch(&tp.quit_at_end), "int 0 Exit at end of video file (implies loop=0)")
139 ("interlace,i", po::bool_switch(&vp.interlaced_source), " Source is interlaced")
140 ("deinterlace,d", po::bool_switch(&vp.deinterlace), " Enable Deinterlacer (requires -i)")
141 ("yrange", po::value(&vp.input_luma_range), "int 220 Range of input luma (white-black+1)")
142 ("yblack", po::value(&vp.input_luma_blacklevel), "int 16 Blacklevel of input luma")
143 ("cblack", po::value(&vp.input_chroma_blacklevel), "int 16 Blacklevel of input chroma")
144 ("out-range", po::value(&vp.output_range), "int 220 Range of R'G'B' output (white-black+1)")
145 ("out-black", po::value(&vp.output_blacklevel), "int 16 Blacklevel of R'G'B' output")
146 ("ymult", po::value(&vp.luminance_mul), "float 1.0 User luma multipler")
147 ("cmult", po::value(&vp.chrominance_mul), "float 1.0 User chroma multiplier")
148 ("yoffset2", po::value(&vp.luminance_offset2), "float 0.0 User luma offset2")
149 ("coffset2", po::value(&vp.chrominance_offset2), "float 0.0 User chroma offset2")
150 ("matrixkr", po::value(&vp.matrix_Kr), "float 0.2126 Luma coefficient Kr")
151 ("matrixkg", po::value(&vp.matrix_Kg), "float 0.7152 Luma coefficient Kg")
152 ("matrixkb", po::value(&vp.matrix_Kb), "float 0.0722 Luma coefficient Kb\n"
153 " ITU-R BT709/BT1361, SMPTE274M/296M")
154 ("sdmatrix,s", " As '-kr 0.299 -kg 0.587 -kb 0.114'\n"
155 " ITU-R BT601/BT470, SMPTE170M/293M")
156 #if WITH_OSD
157 ("fontfile", po::value<string>(), "string TrueType font file for OSD")
158 ("osdscale", po::value(&vp.osd_scale), "float 1.0 OSD size scaling factor")
159 ("osdbackalpha", po::value(&vp.osd_back_alpha),"float 0.7 Transparency for OSD background")
160 ("osdtextalpha", po::value(&vp.osd_text_alpha),"float 0.5 Transparency for OSD text")
161 ("osdstate", po::value(&vp.osd_bot), "int 0 OSD initial state")
162 ("caption", po::value<string>(), "string OSD Caption text")
163 #endif
164 ("filetype,t", po::value<string>(), "string Force file type\n"
165 " [i420|yv12|uyvy|v210|v216]")
166 ("full,f", po::bool_switch(&qt.start_fullscreen)," Start in full screen mode")
167 ("hidemouse", po::bool_switch(&qt.hidemouse), " Never show the mouse pointer")
168 ("video", " Video file to play")
169 ("help", " Show usage information");
171 //file filename is a 'positional option' that we give the name 'video' to
172 po::positional_options_description p;
173 p.add("video", -1);
175 po::variables_map vm;
176 po::store(po::command_line_parser(argc, argv). options(desc).positional(p).run(), vm);
177 po::notify(vm);
179 if (vm.count("help")) {
180 usage();
181 std::cout << desc << std::endl;
182 exit(0);
185 if (vm.count("sd")) {
186 SetLumaCoeffsRec601(vp);
189 if (vm.count("matrixkr") || vm.count("matrixkg") || vm.count("matrixkb")) {
190 if (vp.matrix_Kr + vp.matrix_Kg + vp.matrix_Kb < 1.0)
191 printf("Warning, luma coefficients do not sum to unity\n");
194 #ifdef WITH_OSD
195 if (vm.count("fontfile")) {
196 string tmp = vm["fontfile"].as<string>();
197 vp.font_file = tmp.data();
199 //check OSD font file exists
200 QFileInfo fi(vp.font_file);
201 if(fi.exists() == false) {
202 printf("Cannot find OSD font file %s\n", vp.font_file.toLatin1().data());
203 allParsed = false;
205 else {
206 if(fi.isReadable() == false) {
207 printf("Cannot read OSD font file %s\n", vp.font_file.toLatin1().data());
208 allParsed = false;
213 if(vm.count("caption")) {
214 string tmp = vm["caption"].as<string>();
215 vp.caption = tmp.data();
217 #endif
219 QString known_extensions("i420 yv12 420p 422p 444p uyvy v216 v210 16p4 16p2 16p0");
220 #ifdef HAVE_DIRAC
221 known_extensions.append(" drc");
222 #endif
224 if (vm.count("filetype")) {
225 string tmp = vm["filetype"].as<string>();
226 tp.fileType = tmp.data();
228 if(known_extensions.contains(tp.fileType.toLower(), Qt::CaseInsensitive))
229 tp.forceFileType=true;
230 else {
231 printf("Unknown file type %s\n", tp.fileType.toLatin1().data());
232 allParsed = false;
237 if (vm.count("video") == 0) {
238 printf("No file to play!\n");
239 allParsed = false;
241 else {
242 string tmp = vm["video"].as<string>();
243 tp.fileName = tmp.data();
245 QFileInfo fi(tp.fileName);
247 if(fi.exists()) {
248 if(tp.forceFileType == false) {
249 //file extension must be one we know about
250 if(known_extensions.contains(fi.suffix().toLower(), Qt::CaseInsensitive) == false) {
251 printf("Do not know how to play file with extension %s\n", fi.suffix().toLatin1().data());
252 printf("Please specify file format with the -t flag\n");
253 allParsed = false;
255 else {
256 //the file type has not been forced, and it is an allowed file type
257 tp.fileType = fi.suffix().toLower();
261 else {
262 printf("File %s does not exist\n", tp.fileName.toLatin1().data());
263 allParsed = false;
267 catch(exception& e)
269 printf("Command line error : ");
270 cout << e.what() << "\n";
271 allParsed = false;
274 return allParsed;
277 int main(int argc, char **argv)
279 #ifdef Q_OS_LINUX
280 XInitThreads();
281 #endif
283 struct GLvideo_params vr_params;
284 /* some defaults in the abscence of any settings */
285 vr_params.frame_repeats = 1;
286 vr_params.caption = "hello world";
287 vr_params.osd_scale = 1.;
288 vr_params.osd_back_alpha = 0.7;
289 vr_params.osd_text_alpha = 0.5;
290 vr_params.osd_perf = false;
291 vr_params.osd_bot = OSD_NONE;
292 vr_params.osd_valid = false;
293 vr_params.font_file = DEFAULT_FONTFILE;
294 vr_params.input_luma_range = 220;
295 vr_params.input_luma_blacklevel = 16;
296 vr_params.input_chroma_blacklevel = 128;
297 vr_params.output_blacklevel = 16;
298 vr_params.output_range = 220;
299 vr_params.luminance_mul = 1.;
300 vr_params.chrominance_mul = 1.;
301 vr_params.luminance_offset2 = 0.;
302 vr_params.chrominance_offset2 = 0.;
303 vr_params.interlaced_source = false;
304 vr_params.deinterlace = false;
305 vr_params.matrix_valid = false;
306 SetLumaCoeffsRec709(vr_params);
307 vr_params.aspect_ratio_lock = true;
308 vr_params.show_luma = true;
309 vr_params.show_chroma = true;
311 struct Transport_params t_params;
312 t_params.looping = true;
313 t_params.quit_at_end = false;
314 t_params.forceFileType = false;
315 t_params.videoWidth = 1920;
316 t_params.videoHeight = 1080;
318 struct Qt_params qt_params;
319 qt_params.hidemouse = false;
320 qt_params.start_fullscreen = false;
322 /* QApplication will munge argc/argv, needs to be called before
323 * parseCommandLine. Eg, useful for X11's -display :0 convention */
324 QApplication app(argc, argv);
326 //override settings with command line
327 if (parseCommandLine(argc, argv, vr_params, t_params, qt_params) == false) {
328 return -1;
331 //object containing a seperate thread that manages the lists of frames to be displayed
332 FrameQueue* frameQueue = new FrameQueue();
334 //object that generates frames to be inserted into the frame queue
335 ReaderInterface* reader = NULL;
336 #ifdef HAVE_DIRAC
337 //make dirac reader if required
338 if(t_params.fileType.toLower() == "drc") {
339 DiracReader *r = new DiracReader( *frameQueue );
341 r->setFileName(t_params.fileName);
342 reader = r;
343 r->start(QThread::LowestPriority);
345 #endif
347 //default to YUV reader
348 if (reader == NULL) {
349 YUVReader *r = new YUVReader( *frameQueue );
351 //YUV reader parameters
352 r->setVideoWidth(t_params.videoWidth);
353 r->setVideoHeight(t_params.videoHeight);
354 r->setForceFileType(t_params.forceFileType);
355 r->setFileType(t_params.fileType);
356 r->setFileName(t_params.fileName);
358 reader = r;
361 frameQueue->setReader(reader);
363 //object controlling the video playback 'transport'
364 VideoTransport* vt = new VideoTransport(frameQueue);
366 frameQueue->start();
368 MainWindow* window = new MainWindow(vr_params, qt_params, vt);
370 #ifdef Q_OS_LINUX
371 //shuttlePro jog dial - linux only native support at the moment
372 QShuttlePro* shuttle = new QShuttlePro();
374 //shuttlepro jog wheel
375 QObject::connect(shuttle, SIGNAL(jogForward()), vt, SLOT(transportJogFwd()));
376 QObject::connect(shuttle, SIGNAL(jogBackward()), vt, SLOT(transportJogRev()));
378 //shuttlepro shuttle dial
379 QObject::connect(shuttle, SIGNAL(shuttleRight7()), vt, SLOT(transportFwd100()));
380 QObject::connect(shuttle, SIGNAL(shuttleRight6()), vt, SLOT(transportFwd50()));
381 QObject::connect(shuttle, SIGNAL(shuttleRight5()), vt, SLOT(transportFwd20()));
382 QObject::connect(shuttle, SIGNAL(shuttleRight4()), vt, SLOT(transportFwd10()));
383 QObject::connect(shuttle, SIGNAL(shuttleRight3()), vt, SLOT(transportFwd5()));
384 QObject::connect(shuttle, SIGNAL(shuttleRight2()), vt, SLOT(transportFwd2()));
385 QObject::connect(shuttle, SIGNAL(shuttleRight1()), vt, SLOT(transportFwd1()));
387 QObject::connect(shuttle, SIGNAL(shuttleLeft7()), vt, SLOT(transportRev100()));
388 QObject::connect(shuttle, SIGNAL(shuttleLeft6()), vt, SLOT(transportRev50()));
389 QObject::connect(shuttle, SIGNAL(shuttleLeft5()), vt, SLOT(transportRev20()));
390 QObject::connect(shuttle, SIGNAL(shuttleLeft4()), vt, SLOT(transportRev10()));
391 QObject::connect(shuttle, SIGNAL(shuttleLeft3()), vt, SLOT(transportRev5()));
392 QObject::connect(shuttle, SIGNAL(shuttleLeft2()), vt, SLOT(transportRev2()));
393 QObject::connect(shuttle, SIGNAL(shuttleLeft1()), vt, SLOT(transportRev1()));
394 QObject::connect(shuttle, SIGNAL(shuttleCenter()), vt, SLOT(transportStop()));
396 //shuttlepro buttons
397 QObject::connect(shuttle, SIGNAL(key267Pressed()), vt, SLOT(transportPlayPause()));
398 QObject::connect(shuttle, SIGNAL(key265Pressed()), vt, SLOT(transportFwd1()));
399 QObject::connect(shuttle, SIGNAL(key259Pressed()), window, SLOT(toggleFullScreen()));
400 QObject::connect(shuttle, SIGNAL(key256Pressed()), window, SLOT(toggleOSD()));
401 QObject::connect(shuttle, SIGNAL(key257Pressed()), window, SLOT(toggleAspectLock()));
403 //this is what the IngexPlayer also does
404 //key 269, press=previous mark, hold=start of file
405 //key 270, press=next mark, hold=end of file
406 //key 257, cycle displayed timecode type
407 //key 258, press=lock controls, hold=unlock controls
408 #endif
410 #ifdef Q_OS_UNIX
411 QConsoleInput tty(window);
412 #endif
414 if (t_params.quit_at_end) {
415 QObject::connect(vt, SIGNAL(endOfFile()), &app, SLOT(quit()));
416 t_params.looping = false;
418 vt->setLooping(t_params.looping);
420 window->show();
421 /* app.exec will run until the mainwindow terminates */
422 app.exec();
424 #ifdef Q_OS_LINUX
425 if(shuttle) {
426 shuttle->stop();
427 shuttle->wait();
429 #endif
431 delete window;
432 delete frameQueue;
434 return 0;