1 /* ***** BEGIN LICENSE BLOCK *****
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
25 * ***** END LICENSE BLOCK ***** */
27 #include "mainwindow.h"
33 #include <QApplication>
39 #include <boost/program_options.hpp>
40 namespace po
= boost::program_options
;
42 #include "readerInterface.h"
43 #include "yuvReader.h"
45 #include "diracReader.h"
48 #include "frameQueue.h"
49 #include "videoTransport.h"
51 #include "QShuttlePro.h"
55 #include "QConsoleInput.h"
58 #include "GLvideo_params.h"
62 struct Transport_params
{
75 printf("\nOpenGL accelerated YUV video player.");
77 printf("\nUsage: progname -<flag1> [<flag1_val>] ... <input>");
79 printf("\nSupported file formats:");
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");
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");
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");
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
126 if (getenv("COLUMNS"))
127 cols
= atoi(getenv("COLUMNS"));
130 // Declare the supported options.
131 po::options_description
desc("Allowed options type default description\n"
132 "=============== ==== ======= ===========", cols
);
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")
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")
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
;
175 po::variables_map vm
;
176 po::store(po::command_line_parser(argc
, argv
). options(desc
).positional(p
).run(), vm
);
179 if (vm
.count("help")) {
181 std::cout
<< desc
<< std::endl
;
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");
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());
206 if(fi
.isReadable() == false) {
207 printf("Cannot read OSD font file %s\n", vp
.font_file
.toLatin1().data());
213 if(vm
.count("caption")) {
214 string tmp
= vm
["caption"].as
<string
>();
215 vp
.caption
= tmp
.data();
219 QString
known_extensions("i420 yv12 420p 422p 444p uyvy v216 v210 16p4 16p2 16p0");
221 known_extensions
.append(" drc");
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;
231 printf("Unknown file type %s\n", tp
.fileType
.toLatin1().data());
237 if (vm
.count("video") == 0) {
238 printf("No file to play!\n");
242 string tmp
= vm
["video"].as
<string
>();
243 tp
.fileName
= tmp
.data();
245 QFileInfo
fi(tp
.fileName
);
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");
256 //the file type has not been forced, and it is an allowed file type
257 tp
.fileType
= fi
.suffix().toLower();
262 printf("File %s does not exist\n", tp
.fileName
.toLatin1().data());
269 printf("Command line error : ");
270 cout
<< e
.what() << "\n";
277 int main(int argc
, char **argv
)
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) {
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
;
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
);
343 r
->start(QThread::LowestPriority
);
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
);
361 frameQueue
->setReader(reader
);
363 //object controlling the video playback 'transport'
364 VideoTransport
* vt
= new VideoTransport(frameQueue
);
368 MainWindow
* window
= new MainWindow(vr_params
, qt_params
, vt
);
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()));
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
411 QConsoleInput
tty(window
);
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
);
421 /* app.exec will run until the mainwindow terminates */