1 /* ***** BEGIN LICENSE BLOCK *****
7 * Copyright (c) 2008 BBC Research
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * ***** END LICENSE BLOCK ***** */
29 #include "sequenceReader.h"
31 #include "rawIOv216.h"
32 #include "rawIOv210.h"
33 #include "rawIOYV12.h"
34 #include "rawIOuyvy.h"
37 #include "rawIOuy16.h"
38 #include "rawIOi420.h"
39 #include "rawIOyy16.h"
40 #include "rawIOyyy8.h"
41 #include "rawIO16P4.h"
42 #include "rawIO16P2.h"
43 #include "rawIO16P0.h"
47 #include "rawIOrgba.h"
48 #include "rawIOleader-frm.h"
55 #define _FILE_OFFSET_BITS 64
59 SequenceReader::SequenceReader() :
63 destFrame
= new RawFrame(0, 0, RawFrame::Cr422
); //bogus frame for now
69 //there must be a better way that this to initialise these arrays?
70 rawImageWidth
[SizeQSIF
] = 176; rawImageHeight
[SizeQSIF
] = 120;
71 rawImageWidth
[SizeQCIF
] = 176; rawImageHeight
[SizeQCIF
] = 144;
72 rawImageWidth
[SizeSIF
] = 352; rawImageHeight
[SizeSIF
] = 240;
73 rawImageWidth
[SizeCIF
] = 352; rawImageHeight
[SizeCIF
] = 288;
74 rawImageWidth
[Size4SIF
] = 704; rawImageHeight
[Size4SIF
] = 480;
75 rawImageWidth
[Size4CIF
] = 704; rawImageHeight
[Size4CIF
] = 576;
76 rawImageWidth
[SizeSD480
] = 720; rawImageHeight
[SizeSD480
] = 480;
77 rawImageWidth
[SizeSD576
] = 720; rawImageHeight
[SizeSD576
] = 576;
78 rawImageWidth
[SizeHD720
] = 1280; rawImageHeight
[SizeHD720
] = 720;
79 rawImageWidth
[SizeHD1080
] = 1920; rawImageHeight
[SizeHD1080
] = 1080;
80 rawImageWidth
[Size2K
] = 2048; rawImageHeight
[Size2K
] = 1556;
81 rawImageWidth
[Size4K
] = 4096; rawImageHeight
[Size4K
] = 3112;
82 rawImageWidth
[SizeSHV
] = 7680; rawImageHeight
[SizeSHV
] = 4320;
83 rawImageWidth
[SizeCustom
] = 640; rawImageHeight
[SizeCustom
] = 480;
86 int SequenceReader::getSequenceLength(void)
88 if (fileList
.size() == 0)
91 return lastFrame
- firstFrame
+ 1;
94 int SequenceReader::getFirstFrameNum(void)
99 int SequenceReader::getLastFrameNum(void)
104 int SequenceReader::getCurrentFrameNum(void)
106 return currentFrameNum
;
109 //identify those file types which contain a header giving image dimensions and maybe other useful stuff
110 bool SequenceReader::hasHeader(RawType type
)
115 case type_leader_frm
:
130 //for raw file types we can sometimes know the bit depth given the file extension
131 int SequenceReader::bitDepth(RawType type
)
137 depth
= 0; //we don't know what the depth of this file is
170 //convert a file extension into the enumerated file type
171 SequenceReader::RawType
SequenceReader::rawType(QString
&ext
)
180 else if (ext
== "v216") {
183 else if (ext
== "uy16") {
186 else if (ext
== "yv12") {
189 else if (ext
== "i420") {
192 else if (ext
== "uyvy") {
195 else if (ext
== "yy16") {
198 else if (ext
== "yyy8") {
201 else if (ext
== "16p4") {
204 else if (ext
== "16p2") {
207 else if (ext
== "16p0") {
210 else if (ext
== "frm" || ext
== "FRM") {
211 type
= type_leader_frm
;
213 else if (ext
== "pgm") {
216 else if (ext
== "pnm") { //hack
219 else if (ext
== "ppm") {
222 else if (ext
== "sgi") {
225 else if (ext
== "8p2") {
228 else if (ext
== "rgb")
232 else if (ext
== "rgba")
243 //convert a file extension into enumerated chroma type
244 RawFrame::Chroma
SequenceReader::chromaType(RawType type
)
246 RawFrame::Chroma inChroma
;
255 inChroma
= RawFrame::Cr422
;
261 inChroma
= RawFrame::Cr420
;
265 inChroma
= RawFrame::Cr444
;
271 inChroma
= RawFrame::YOnly
;
278 inChroma
= RawFrame::CrRGB
;
281 case type_leader_frm
: /* for leader, this is overridden later */
283 inChroma
= RawFrame::Cr422
;
290 //return the number of bytes per frame for simple concatenated file types, or 0 for other types
291 int SequenceReader::bytesPerFrame(RawType type
)
298 bpf
= rawWidth
* rawHeight
* 2 * 3;
302 bpf
= ((rawWidth
+ 47)/48) * 48 * rawHeight
* 2 * 4 / 3;
308 bpf
= rawWidth
* rawHeight
* 2 * 2;
312 bpf
= rawWidth
* rawHeight
* 2 * 3 / 2;
317 bpf
= rawWidth
* rawHeight
* 3 / 2;
322 bpf
= rawWidth
* rawHeight
* 2;
326 bpf
= rawWidth
* rawHeight
;
330 bpf
= rawWidth
* rawHeight
* 2;
334 bpf
= rawWidth
* rawHeight
* 3;
338 bpf
= rawWidth
* rawHeight
* 4;
349 void SequenceReader::setRawFormat(RawType format
)
353 //if we have any files, the info will have changed
354 if (fileList
.size() > 0)
357 readFrame(currentFrameNum
);
360 //open a directory full of files
361 int SequenceReader::setDirectoryOfFiles(const QString
&dir
)
363 //get directory contents with the extension of the selected file
364 //sorted by name, selecting only files not directories
368 QString("*.v210 *.uy16 *.v216 *.yv12 *.i420 *.16P4 *.16P2 *16P0 *.uyvy *.yuv *.yyy8 *.yy16 *.8P2 *.rgb *.rgba"),
369 QDir::Name
, QDir::Files
);
371 if (dirInfo
.count() == 0)
374 QFileInfoList fileInfoList
= dirInfo
.entryInfoList();
376 for (unsigned int i
=0; i
<dirInfo
.count(); i
++)
377 list
.append(fileInfoList
[i
].absoluteFilePath());
379 fileList
= list
; //replace the old file list with the new one
381 if (filePtr
!= NULL
) {
386 //build file information for the new file list
393 //given a list of filenames, generate the complete list of filenames in a sequence
394 //if the filename is numerical, subsequent files of the same extension are added to the list
395 int SequenceReader::setFileNames(const QStringList
&newFileList
)
397 //check for empty list
398 if (newFileList
.size() == 0) {
399 //tried to open an empty file list
403 //check that all the files in the list have a recognised extension
404 for (int i
=0; i
<newFileList
.size(); i
++) {
405 QFileInfo
info(newFileList
.at(i
));
406 QString ext
= info
.suffix();
408 //look for unknown file extensions
409 if ((rawType(ext
) == type_unknown
) && (frameType
== type_auto
))
410 //unknown file extension
414 QStringList list
= newFileList
;
415 QFileInfo
firstFileInfo(list
.at(0));
416 bool firstIsNumerical
= false;
417 firstFileInfo
.baseName().toInt(&firstIsNumerical
, 10);
419 //if there is a single entry in the file list, and the file name is a number,
420 //look for other files _after_ this one with the same extension, sorted by name
421 if (list
.size() == 1 && firstIsNumerical
) {
423 QString ext
= firstFileInfo
.suffix();
424 QString name
= firstFileInfo
.fileName();
426 //get directory contents with the extension of the selected file
427 //sorted by name, selecting only files not directories
428 QDir
dirInfo(firstFileInfo
.absolutePath(), QString("*." + ext
),
429 QDir::Name
, QDir::Files
);
431 //it is possible to iterate over the dirInfo.entryList, but this is horribly slow
432 //instead, get a QFileInfoList which is very fast to access
433 QFileInfoList fileInfoList
= dirInfo
.entryInfoList();
435 //add to the file list all files which occur after the specified one
437 for (int i
= 0; i
< fileInfoList
.size(); ++i
) {
439 //once we have found the selected file in the directory, add subsequent ones to the file list
441 list
.append(fileInfoList
[i
].absoluteFilePath());
443 //detect when the selected file has been found in the directory listing
444 if (found
== false && (fileInfoList
[i
].fileName() == name
))
449 //we have built the new file list. Use this instead of the old one now.
451 currentFileIndex
= 0;
452 if (filePtr
!= NULL
) {
457 //build file information for the new file list
464 void SequenceReader::buildFileInfo()
467 QFileInfo
firstFileInfo(fileList
.at(0));
469 firstFrame
= firstFileInfo
.baseName().toInt(NULL
, 10);
470 int firstInFile
= firstFrame
;
471 lastFrame
= firstFrame
;
473 //for each file in the list, get the info on it
474 for (int i
=0; i
<fileList
.size(); i
++) {
476 QFileInfo
fileInfo(fileList
.at(i
));
477 QString ext
= fileInfo
.suffix();
479 sequenceFileInfo sfi
;
481 if (frameType
== type_auto
)
482 sfi
.rawType
= rawType(ext
);
484 sfi
.rawType
= frameType
;
486 sfi
.bytesPerFrame
= bytesPerFrame(sfi
.rawType
);
488 //determine the number of frames in a file, avoiding a division by zero
489 if (sfi
.bytesPerFrame
> 0) {
490 sfi
.framesInFile
= (int)(fileInfo
.size() / sfi
.bytesPerFrame
);
493 sfi
.framesInFile
= 0;
496 //there is at least one frame, even if the file is too small for bytesPerFrame
497 if (sfi
.framesInFile
== 0)
498 sfi
.framesInFile
= 1;
500 sfi
.bitDepth
= bitDepth(sfi
.rawType
);
501 sfi
.hasHeader
= hasHeader(sfi
.rawType
);
502 sfi
.chroma
= chromaType(sfi
.rawType
);
503 sfi
.firstFrameNum
= firstInFile
;
504 sfi
.lastFrameNum
= firstInFile
+ sfi
.framesInFile
- 1;
506 infoList
.push_back(sfi
);
508 firstInFile
+= sfi
.framesInFile
; //first frame number in next file
509 lastFrame
= sfi
.lastFrameNum
; //last frame number in the sequence
514 printf("First frame is %d\n", firstFrame
);
515 printf("Last frame is %d\n", lastFrame
);
516 printf("Raw width is %d\n", rawWidth
);
517 printf("Raw Height is %d\n", rawHeight
);
519 //dump the file list, for interest
520 for (int i
=0; i
<fileList
.size(); i
++) {
521 printf("File list entry %d (%s)\n", i
, fileList
.at(i
).toLatin1().data());
522 printf(" File info bytesPerFrame = %d\n", infoList
.at(i
).bytesPerFrame
);
523 printf(" File info chroma = %d\n", (int)infoList
.at(i
).chroma
);
524 printf(" File info has header = %d\n", (int)infoList
.at(i
).hasHeader
);
525 printf(" File info bit depth = %d\n", infoList
.at(i
).bitDepth
);
526 printf(" File info framesInFile = %d\n", infoList
.at(i
).framesInFile
);
527 printf(" File info firstFrameNum = %d\n", infoList
.at(i
).firstFrameNum
);
528 printf(" File info lastFrameNum = %d\n", infoList
.at(i
).lastFrameNum
);
532 //sanity check on currentFrameNum, as the frame numbering may have changed
533 if (currentFrameNum
< firstFrame
)
534 currentFrameNum
= firstFrame
;
536 if (currentFrameNum
> lastFrame
)
537 currentFrameNum
= lastFrame
;
540 int SequenceReader::fileIndexForFrameNum(int frameNum
)
544 if (frameNum
> currentFrameNum
) {
547 for (int i
=currentFileIndex
; i
<(int)infoList
.size(); i
++) {
549 if (frameNum
>= infoList
.at(i
).firstFrameNum
&& frameNum
<= infoList
.at(i
).lastFrameNum
) {
559 for (int i
=currentFileIndex
; i
>0; i
--) {
560 if (frameNum
>= infoList
.at(i
).firstFrameNum
&& frameNum
<= infoList
.at(i
).lastFrameNum
) {
571 void SequenceReader::nextInSequence()
573 readFrame(currentFrameNum
+1);
576 void SequenceReader::prevInSequence()
578 readFrame(currentFrameNum
-1);
581 //move to a frame number in the sequence
582 int SequenceReader::jumpInSequence(int wantedFrame
)
585 if (wantedFrame
> lastFrame
|| wantedFrame
< firstFrame
)
588 if(fileList
.size() < 1)
591 //get the file index for the wanted frame number
592 int newFileIndex
= fileIndexForFrameNum(wantedFrame
);
594 //see if we have that file open at the moment
595 if (newFileIndex
!= currentFileIndex
|| filePtr
== NULL
) {
596 //open a the new file
597 currentFileIndex
= newFileIndex
;
602 filePtr
= fopen(fileList
.at(currentFileIndex
).toLatin1().data(), "rb");
603 emit(frameFileName(fileList
.at(currentFileIndex
)));
606 if (filePtr
== NULL
) {
610 //seek to the position of the wanted frame in the current file
611 off_t frameOffset
= wantedFrame
- infoList
.at(currentFileIndex
).firstFrameNum
;
612 off_t byteOffset
= frameOffset
* infoList
.at(currentFileIndex
).bytesPerFrame
;
617 if(_fseeki64(filePtr
, byteOffset
, SEEK_SET
)) {
619 if(fseek(filePtr
, byteOffset
, SEEK_SET
)) {
624 if(fseeko64(filePtr
, byteOffset
, SEEK_SET
)) {
629 if(fseeko(filePtr
, byteOffset
, SEEK_SET
)) {
635 currentFrameNum
= wantedFrame
;
637 QFileInfo
fi(fileList
.at(currentFileIndex
));
639 emit(sequencePosition(fi
.fileName(), currentFrameNum
- infoList
.at(currentFileIndex
).firstFrameNum
, firstFrame
, currentFrameNum
, lastFrame
));
645 //read a particular frame number
646 RawFrame
& SequenceReader::readFrame(int frameNum
)
648 if(fileList
.size()> 0) {
650 jumpInSequence(frameNum
);
654 //select either the frame type from the extension, or the user selected override
657 if(infoList
.at(currentFileIndex
).hasHeader
) {
658 type
= infoList
.at(currentFileIndex
).rawType
;
661 type
= (frameType
== type_auto
) ? infoList
.at(currentFileIndex
).rawType
: frameType
;
667 emit(frameFormat(QString("YYY8 (Yonly) 8Bit")));
668 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
669 r
= new RawReaderYYY8(filePtr
);
673 emit(frameFormat(QString("YY16 (Yonly) 16Bit")));
674 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
675 r
= new RawReaderYY16(filePtr
);
679 emit(frameFormat(QString("V216 4:2:2 16Bit muxed")));
680 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
681 r
= new RawReaderV216(filePtr
);
685 emit(frameFormat(QString("UY16 4:2:2 16Bit muxed")));
686 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
687 r
= new RawReaderUY16(filePtr
);
691 emit(frameFormat(QString("V210 4:2:2 10Bit packed")));
692 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
693 r
= new RawReaderv210(filePtr
);
697 emit(frameFormat(QString("YV12 4:2:0 8Bit planar YVU")));
698 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
699 r
= new RawReaderYV12(filePtr
);
703 emit(frameFormat(QString("I420 4:2:0 8Bit planar YUV")));
704 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
705 r
= new RawReaderi420(filePtr
);
709 emit(frameFormat(QString("16P4 4:4:4 16Bit planar YUV")));
710 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
711 r
= new RawReader16P4(filePtr
);
715 emit(frameFormat(QString("16P2 4:2:2 16Bit planar YUV")));
716 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
717 r
= new RawReader16P2(filePtr
);
721 emit(frameFormat(QString("16P0 4:2:0 16Bit planar YUV")));
722 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
723 r
= new RawReader16P0(filePtr
);
727 emit(frameFormat(QString("UYVY 4:2:2 8Bit muxed")));
728 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
729 r
= new RawReaderuyvy(filePtr
);
733 emit(frameFormat(QString("RGB 8Bit muxed")));
734 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
735 r
= new RawReaderrgb(filePtr
);
739 emit(frameFormat(QString("RGBA 8Bit muxed")));
740 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
741 r
= new RawReaderrgba(filePtr
);
744 case type_leader_frm
:
745 r
= new RawReaderLeaderFRM(filePtr
);
746 emit(frameFormat(QString("Leader RAW FRM (%1 bits)") .arg(r
->getDepth())));
747 emit(frameBitDepth(r
->getDepth()));
751 r
= new RawReaderpgm(filePtr
);
752 emit(frameFormat(QString("Portable Greymap (%1 bits)") .arg(r
->getDepth())));
753 emit(frameBitDepth(r
->getDepth()));
757 r
= new RawReaderppm(filePtr
);
758 emit(frameFormat(QString("Portable Pixmap (%1 bits)") .arg(r
->getDepth())));
759 emit(frameBitDepth(r
->getDepth()));
763 r
= new RawReadersgi(filePtr
);
764 emit(frameFormat(QString("SGI file (%1 bits)") .arg(r
->getDepth())));
765 emit(frameBitDepth(r
->getDepth()));
769 r
= new RawReader8P2(filePtr
);
770 emit(frameFormat(QString("8P2 4:2:2 8Bit planar YUV")));
771 emit(frameBitDepth(infoList
.at(currentFileIndex
).bitDepth
));
775 emit(frameFormat(QString("File of unknown type '%1'") .arg(fileList
.at(currentFileIndex
))));
776 emit(frameBitDepth(0));
780 //check if the frame dimensions can be read from the frame header
781 emit(frameHasHeader(infoList
.at(currentFileIndex
).hasHeader
));
783 if(infoList
.at(currentFileIndex
).hasHeader
) {
784 frameWidth
= r
->getWidth();
785 frameHeight
= r
->getHeight();
786 frameDepth
= r
->getDepth();
789 frameDepth
= infoList
.at(currentFileIndex
).bitDepth
;
790 frameWidth
= rawWidth
;
791 frameHeight
= rawHeight
;
794 //determine the chroma type that we will read into
795 //this is set either by the file extension or the image->image format menu
796 RawFrame::Chroma chroma
;
797 if (frameType
== type_leader_frm
)
798 chroma
= ((RawReaderLeaderFRM
*)r
)->getChroma();
799 else if(frameType
== type_auto
)
800 chroma
= infoList
.at(currentFileIndex
).chroma
;
802 chroma
= chromaType(frameType
);
804 //sanity checks - is the destination frame type correct?
805 if(destFrame
->chroma
!= chroma
||
806 destFrame
->luma
.width() != frameWidth
||
807 destFrame
->luma
.height() != frameHeight
) {
809 destFrame
= new RawFrame(frameWidth
, frameHeight
, chroma
);
818 emit
newFrame(destFrame
);
819 emit
frameHasHeader(infoList
.at(currentFileIndex
).hasHeader
);
821 QSize s
= QSize(frameWidth
, frameHeight
);
828 void SequenceReader::setSizeType(ImageSizes s
)
830 rawWidth
= rawImageWidth
[s
];
831 rawHeight
= rawImageHeight
[s
];
833 //if we have any files, the info will have changed
834 if (fileList
.size() > 0)
837 readFrame(currentFrameNum
);
840 //the dimensions of the frame are changed
841 void SequenceReader::setCustomSize(int width
, int height
)
843 rawImageWidth
[SizeCustom
] = width
;
844 rawImageHeight
[SizeCustom
] = height
;
847 int SequenceReader::getCustomWidth() {
848 return rawImageWidth
[SizeCustom
];
851 int SequenceReader::getCustomHeight() {
852 return rawImageHeight
[SizeCustom
];
855 bool SequenceReader::getFrameHasHeader(void)
857 bool hasHeader
= false;
859 if (infoList
.size() > 0)
860 hasHeader
= infoList
.at(currentFileIndex
).hasHeader
;