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"
44 #include "yuvReaderMmap.h"
46 #include "diracReader.h"
49 #include "frameQueue.h"
50 #include "videoTransport.h"
52 #include "QShuttlePro.h"
56 #include "QConsoleInput.h"
59 #include "GLvideo_params.h"
63 struct Transport_params
{
76 printf("\nOpenGL accelerated YUV video player.");
78 printf("\nUsage: progname -<flag1> [<flag1_val>] ... <input>");
80 printf("\nSupported file formats:");
82 printf("\n .i420 4:2:0 YUV 8 bit planar");
83 printf("\n .yv12 4:2:0 YVU 8 bit planar");
84 printf("\n .420p 4:2:0 YUV 8 bit planar");
85 printf("\n .422p 4:2:2 YUV 8 bit planar");
86 printf("\n .444p 4:4:4 YUV 8 bit planar");
87 printf("\n .uyvy 4:2:2 YUV 8 bit packed");
88 printf("\n .v210 4:2:2 YUV 10 bit packed");
89 printf("\n .v216 4:2:2 YUV 16 bit packed");
90 printf("\n .16p0 4:2:0 YUV 16 bit planar");
91 printf("\n .16p2 4:2:2 YUV 16 bit planar");
92 printf("\n .16p4 4:4:4 YUV 16 bit planar");
95 printf("\nKeypress Action");
96 printf("\n======== ======");
97 printf("\no Toggle OSD state");
98 printf("\nf Toggle full screen mode");
99 printf("\nm Switch to output levels from user flags out-range and out-black");
100 printf("\nn Switch to video output levels, out-range=240 out-black=16");
101 printf("\nb Switch to computer output levels, out-range=256, out-black=0");
102 printf("\nEsc Return from full screen mode to windowed");
103 printf("\na Toggle aspect ratio lock");
104 printf("\nd Toggle deinterlacing of an interlaced source");
105 printf("\nSpace Play/Pause");
107 printf("\n1,2,3,4,5,6,7 Play forward at 1,2,5,10,20,50,100x");
108 printf("\nCTRL + 1,2,3,4,5,6,7 Play backward at 1,2,5,10,20,50,100x");
109 printf("\n> Jog one frame forward when paused");
110 printf("\n< Jog one frame backward when paused");
111 printf("\ny Toggle display of luma on/off");
112 printf("\nc Toggle display of chroma on/off");
113 printf("\nh Switch to HDTV colour matrix kr=0.2126 kg=0.7152 kb=0.0722");
114 printf("\nj Switch to SDTV colour matrix kr=0.2990 kg=0.5870 kb=0.1140");
115 printf("\nk Switch to colour matrix kr, kg, kb from user flags");
122 parseCommandLine(int argc
, char **argv
, GLvideo_params
& vp
, Transport_params
& tp
, Qt_params
& qt
)
124 bool allParsed
= true; //default to command line parsing succeeding
127 if (getenv("COLUMNS"))
128 cols
= atoi(getenv("COLUMNS"));
131 // Declare the supported options.
132 po::options_description
desc("Allowed options type default description\n"
133 "=============== ==== ======= ===========", cols
);
135 ("width,w", po::value(&tp
.videoWidth
), "int 1920 Width of video luma component")
136 ("height,h", po::value(&tp
.videoHeight
), "int 1080 Height of video luma component")
137 ("repeats,r", po::value(&vp
.frame_repeats
), "int 0 Frame is repeated r extra times")
138 ("loop,l", po::value(&tp
.looping
), "int 1 Number of times to loop video (1=inf)")
139 ("quit,q", po::bool_switch(&tp
.quit_at_end
), "int 0 Exit at end of video file (implies loop=0)")
140 ("interlace,i", po::bool_switch(&vp
.interlaced_source
), " Source is interlaced")
141 ("deinterlace,d", po::bool_switch(&vp
.deinterlace
), " Enable Deinterlacer (requires -i)")
142 ("yrange", po::value(&vp
.input_luma_range
), "int 220 Range of input luma (white-black+1)")
143 ("yblack", po::value(&vp
.input_luma_blacklevel
), "int 16 Blacklevel of input luma")
144 ("cblack", po::value(&vp
.input_chroma_blacklevel
), "int 16 Blacklevel of input chroma")
145 ("out-range", po::value(&vp
.output_range
), "int 220 Range of R'G'B' output (white-black+1)")
146 ("out-black", po::value(&vp
.output_blacklevel
), "int 16 Blacklevel of R'G'B' output")
147 ("ymult", po::value(&vp
.luminance_mul
), "float 1.0 User luma multipler")
148 ("cmult", po::value(&vp
.chrominance_mul
), "float 1.0 User chroma multiplier")
149 ("yoffset2", po::value(&vp
.luminance_offset2
), "float 0.0 User luma offset2")
150 ("coffset2", po::value(&vp
.chrominance_offset2
), "float 0.0 User chroma offset2")
151 ("matrixkr", po::value(&vp
.matrix_Kr
), "float 0.2126 Luma coefficient Kr")
152 ("matrixkg", po::value(&vp
.matrix_Kg
), "float 0.7152 Luma coefficient Kg")
153 ("matrixkb", po::value(&vp
.matrix_Kb
), "float 0.0722 Luma coefficient Kb\n"
154 " ITU-R BT709/BT1361, SMPTE274M/296M")
155 ("sdmatrix,s", " As '-kr 0.299 -kg 0.587 -kb 0.114'\n"
156 " ITU-R BT601/BT470, SMPTE170M/293M")
158 ("fontfile", po::value
<string
>(), "string TrueType font file for OSD")
159 ("osdscale", po::value(&vp
.osd_scale
), "float 1.0 OSD size scaling factor")
160 ("osdbackalpha", po::value(&vp
.osd_back_alpha
),"float 0.7 Transparency for OSD background")
161 ("osdtextalpha", po::value(&vp
.osd_text_alpha
),"float 0.5 Transparency for OSD text")
162 ("osdstate", po::value(&vp
.osd_bot
), "int 0 OSD initial state")
163 ("caption", po::value
<string
>(), "string OSD Caption text")
165 ("filetype,t", po::value
<string
>(), "string Force file type\n"
166 " [i420|yv12|uyvy|v210|v216]")
167 ("full,f", po::bool_switch(&qt
.start_fullscreen
)," Start in full screen mode")
168 ("hidemouse", po::bool_switch(&qt
.hidemouse
), " Never show the mouse pointer")
169 ("video", " Video file to play")
170 ("help", " Show usage information");
172 //file filename is a 'positional option' that we give the name 'video' to
173 po::positional_options_description p
;
176 po::variables_map vm
;
177 po::store(po::command_line_parser(argc
, argv
). options(desc
).positional(p
).run(), vm
);
180 if (vm
.count("help")) {
182 std::cout
<< desc
<< std::endl
;
186 if (vm
.count("sd")) {
187 SetLumaCoeffsRec601(vp
);
190 if (vm
.count("matrixkr") || vm
.count("matrixkg") || vm
.count("matrixkb")) {
191 if (vp
.matrix_Kr
+ vp
.matrix_Kg
+ vp
.matrix_Kb
< 1.0)
192 printf("Warning, luma coefficients do not sum to unity\n");
196 if (vm
.count("fontfile")) {
197 string tmp
= vm
["fontfile"].as
<string
>();
198 vp
.font_file
= tmp
.data();
200 //check OSD font file exists
201 QFileInfo
fi(vp
.font_file
);
202 if(fi
.exists() == false) {
203 printf("Cannot find OSD font file %s\n", vp
.font_file
.toLatin1().data());
207 if(fi
.isReadable() == false) {
208 printf("Cannot read OSD font file %s\n", vp
.font_file
.toLatin1().data());
214 if(vm
.count("caption")) {
215 string tmp
= vm
["caption"].as
<string
>();
216 vp
.caption
= tmp
.data();
220 QString
known_extensions("i420 yv12 420p 422p 444p uyvy v216 v210 16p4 16p2 16p0");
222 known_extensions
.append(" drc");
225 if (vm
.count("filetype")) {
226 string tmp
= vm
["filetype"].as
<string
>();
227 tp
.fileType
= tmp
.data();
229 if(known_extensions
.contains(tp
.fileType
.toLower(), Qt::CaseInsensitive
))
230 tp
.forceFileType
=true;
232 printf("Unknown file type %s\n", tp
.fileType
.toLatin1().data());
238 if (vm
.count("video") == 0) {
239 printf("No file to play!\n");
243 string tmp
= vm
["video"].as
<string
>();
244 tp
.fileName
= tmp
.data();
246 QFileInfo
fi(tp
.fileName
);
249 if(tp
.forceFileType
== false) {
250 //file extension must be one we know about
251 if(known_extensions
.contains(fi
.suffix().toLower(), Qt::CaseInsensitive
) == false) {
252 printf("Do not know how to play file with extension %s\n", fi
.suffix().toLatin1().data());
253 printf("Please specify file format with the -t flag\n");
257 //the file type has not been forced, and it is an allowed file type
258 tp
.fileType
= fi
.suffix().toLower();
263 printf("File %s does not exist\n", tp
.fileName
.toLatin1().data());
270 printf("Command line error : ");
271 cout
<< e
.what() << "\n";
278 int main(int argc
, char **argv
)
284 struct GLvideo_params vr_params
;
285 /* some defaults in the abscence of any settings */
286 vr_params
.frame_repeats
= 1;
287 vr_params
.caption
= "hello world";
288 vr_params
.osd_scale
= 1.;
289 vr_params
.osd_back_alpha
= 0.7;
290 vr_params
.osd_text_alpha
= 0.5;
291 vr_params
.osd_perf
= false;
292 vr_params
.osd_bot
= OSD_NONE
;
293 vr_params
.osd_valid
= false;
294 vr_params
.font_file
= DEFAULT_FONTFILE
;
295 vr_params
.input_luma_range
= 220;
296 vr_params
.input_luma_blacklevel
= 16;
297 vr_params
.input_chroma_blacklevel
= 128;
298 vr_params
.output_blacklevel
= 16;
299 vr_params
.output_range
= 220;
300 vr_params
.luminance_mul
= 1.;
301 vr_params
.chrominance_mul
= 1.;
302 vr_params
.luminance_offset2
= 0.;
303 vr_params
.chrominance_offset2
= 0.;
304 vr_params
.interlaced_source
= false;
305 vr_params
.deinterlace
= false;
306 vr_params
.matrix_valid
= false;
307 SetLumaCoeffsRec709(vr_params
);
308 vr_params
.aspect_ratio_lock
= true;
309 vr_params
.show_luma
= true;
310 vr_params
.show_chroma
= true;
312 struct Transport_params t_params
;
313 t_params
.looping
= true;
314 t_params
.quit_at_end
= false;
315 t_params
.forceFileType
= false;
316 t_params
.videoWidth
= 1920;
317 t_params
.videoHeight
= 1080;
319 struct Qt_params qt_params
;
320 qt_params
.hidemouse
= false;
321 qt_params
.start_fullscreen
= false;
323 /* QApplication will munge argc/argv, needs to be called before
324 * parseCommandLine. Eg, useful for X11's -display :0 convention */
325 QApplication
app(argc
, argv
);
327 //override settings with command line
328 if (parseCommandLine(argc
, argv
, vr_params
, t_params
, qt_params
) == false) {
332 //object containing a seperate thread that manages the lists of frames to be displayed
333 FrameQueue
* frameQueue
= new FrameQueue();
335 //object that generates frames to be inserted into the frame queue
336 ReaderInterface
* reader
= NULL
;
338 //make dirac reader if required
339 if(t_params
.fileType
.toLower() == "drc") {
340 DiracReader
*r
= new DiracReader( *frameQueue
);
342 r
->setFileName(t_params
.fileName
);
344 r
->start(QThread::LowestPriority
);
348 //default to YUV reader
349 if (reader
== NULL
) {
351 YUVReaderMmap
*r
= new YUVReaderMmap( *frameQueue
);
353 YUVReader
*r
= new YUVReader( *frameQueue
);
355 //YUV reader parameters
356 r
->setVideoWidth(t_params
.videoWidth
);
357 r
->setVideoHeight(t_params
.videoHeight
);
358 r
->setForceFileType(t_params
.forceFileType
);
359 r
->setFileType(t_params
.fileType
);
360 r
->setFileName(t_params
.fileName
);
365 frameQueue
->setReader(reader
);
367 //object controlling the video playback 'transport'
368 VideoTransport
* vt
= new VideoTransport(frameQueue
);
372 MainWindow
* window
= new MainWindow(vr_params
, qt_params
, vt
);
375 //shuttlePro jog dial - linux only native support at the moment
376 QShuttlePro
* shuttle
= new QShuttlePro();
378 //shuttlepro jog wheel
379 QObject::connect(shuttle
, SIGNAL(jogForward()), vt
, SLOT(transportJogFwd()));
380 QObject::connect(shuttle
, SIGNAL(jogBackward()), vt
, SLOT(transportJogRev()));
382 //shuttlepro shuttle dial
383 QObject::connect(shuttle
, SIGNAL(shuttleRight7()), vt
, SLOT(transportFwd100()));
384 QObject::connect(shuttle
, SIGNAL(shuttleRight6()), vt
, SLOT(transportFwd50()));
385 QObject::connect(shuttle
, SIGNAL(shuttleRight5()), vt
, SLOT(transportFwd20()));
386 QObject::connect(shuttle
, SIGNAL(shuttleRight4()), vt
, SLOT(transportFwd10()));
387 QObject::connect(shuttle
, SIGNAL(shuttleRight3()), vt
, SLOT(transportFwd5()));
388 QObject::connect(shuttle
, SIGNAL(shuttleRight2()), vt
, SLOT(transportFwd2()));
389 QObject::connect(shuttle
, SIGNAL(shuttleRight1()), vt
, SLOT(transportFwd1()));
391 QObject::connect(shuttle
, SIGNAL(shuttleLeft7()), vt
, SLOT(transportRev100()));
392 QObject::connect(shuttle
, SIGNAL(shuttleLeft6()), vt
, SLOT(transportRev50()));
393 QObject::connect(shuttle
, SIGNAL(shuttleLeft5()), vt
, SLOT(transportRev20()));
394 QObject::connect(shuttle
, SIGNAL(shuttleLeft4()), vt
, SLOT(transportRev10()));
395 QObject::connect(shuttle
, SIGNAL(shuttleLeft3()), vt
, SLOT(transportRev5()));
396 QObject::connect(shuttle
, SIGNAL(shuttleLeft2()), vt
, SLOT(transportRev2()));
397 QObject::connect(shuttle
, SIGNAL(shuttleLeft1()), vt
, SLOT(transportRev1()));
398 QObject::connect(shuttle
, SIGNAL(shuttleCenter()), vt
, SLOT(transportStop()));
401 QObject::connect(shuttle
, SIGNAL(key267Pressed()), vt
, SLOT(transportPlayPause()));
402 QObject::connect(shuttle
, SIGNAL(key265Pressed()), vt
, SLOT(transportFwd1()));
403 QObject::connect(shuttle
, SIGNAL(key259Pressed()), window
, SLOT(toggleFullScreen()));
404 QObject::connect(shuttle
, SIGNAL(key256Pressed()), window
, SLOT(toggleOSD()));
405 QObject::connect(shuttle
, SIGNAL(key257Pressed()), window
, SLOT(toggleAspectLock()));
407 //this is what the IngexPlayer also does
408 //key 269, press=previous mark, hold=start of file
409 //key 270, press=next mark, hold=end of file
410 //key 257, cycle displayed timecode type
411 //key 258, press=lock controls, hold=unlock controls
415 QConsoleInput
tty(window
);
418 if (t_params
.quit_at_end
) {
419 QObject::connect(vt
, SIGNAL(endOfFile()), &app
, SLOT(quit()));
420 t_params
.looping
= false;
422 vt
->setLooping(t_params
.looping
);
425 /* app.exec will run until the mainwindow terminates */