[Scummvm-git-logs] scummvm master -> 00a5c879346e0d347ecf32e26ea9a28d9218a75a
sev-
noreply at scummvm.org
Sun Jun 30 18:44:00 UTC 2024
This automated email contains information about 11 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
d4fa4dde30 COMMON: FORMATS: Implement NAVG atom parsing for QuickTime movies
4a180f94f5 COMMON: FORMATS: Implement ctyp atom parsing for QuickTime movies
fc34902998 COMMON: FORMATS: Implement pInf atom parsing for QuickTime movies
d704b8e959 COMMON: FORMATS: Implement vmhd atom parsing for QuickTime movies
5e6b127a8c COMMON: FORMATS: Implement gmin atom parsing for QuickTime movies
5d0c745783 COMMON: FORMATS: Implement WLOC atom parsing for QuickTime movies
9596bf04a8 COMMON: FORMATS: Implement smhd atom parsing for QuickTime movies
e4624cf95b COMMON: Implement interactive control for QuickTime object movies
01c2def795 TESTBED: Enable mouse event handling for QuickTime interactivity
c39c63af3a COMMON: FORMATS: Add support for parsing QuickTime VR panorama atoms
00a5c87934 VIDEO: Implement rendering of panorama movie in QuickTime (WIP)
Commit: d4fa4dde30b74d5b565936f1e28aecaf38dae946
https://github.com/scummvm/scummvm/commit/d4fa4dde30b74d5b565936f1e28aecaf38dae946
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
COMMON: FORMATS: Implement NAVG atom parsing for QuickTime movies
This commit implements NAVG (Navigation) atom parsing for QuickTime movies.
It contains information about the movie's navigation.
Changed paths:
common/formats/quicktime.cpp
common/formats/quicktime.h
diff --git a/common/formats/quicktime.cpp b/common/formats/quicktime.cpp
index abd9b39f56f..9cd40405f0c 100644
--- a/common/formats/quicktime.cpp
+++ b/common/formats/quicktime.cpp
@@ -160,7 +160,8 @@ void QuickTimeParser::initParseTable() {
{ &QuickTimeParser::readSTTS, MKTAG('s', 't', 't', 's') },
{ &QuickTimeParser::readTKHD, MKTAG('t', 'k', 'h', 'd') },
{ &QuickTimeParser::readTRAK, MKTAG('t', 'r', 'a', 'k') },
- { &QuickTimeParser::readLeaf, MKTAG('u', 'd', 't', 'a') },
+ { &QuickTimeParser::readDefault, MKTAG('u', 'd', 't', 'a') },
+ { &QuickTimeParser::readNAVG, MKTAG('N', 'A', 'V', 'G') },
{ &QuickTimeParser::readLeaf, MKTAG('v', 'm', 'h', 'd') },
{ &QuickTimeParser::readCMOV, MKTAG('c', 'm', 'o', 'v') },
{ &QuickTimeParser::readWAVE, MKTAG('w', 'a', 'v', 'e') },
@@ -798,6 +799,36 @@ int QuickTimeParser::readSMI(Atom atom) {
return 0;
}
+static float readAppleFloatField(SeekableReadStream *stream) {
+ int16 a = stream->readSint16BE();
+ uint16 b = stream->readUint16BE();
+
+ float value = (float)a + (float)b / 65536.0f;
+
+ return value;
+}
+
+int QuickTimeParser::readNAVG(Atom atom) {
+ _fd->readUint16BE(); // version
+ _nav.columns = _fd->readUint16BE();
+ _nav.rows = _fd->readUint16BE();
+ _fd->readUint16BE(); // reserved
+ _nav.loop_size = _fd->readUint16BE();
+ _nav.frame_duration = _fd->readUint16BE();
+ _nav.movie_type = (MovieType)_fd->readUint16BE();
+ _nav.loop_ticks = _fd->readUint16BE();
+ _nav.field_of_view = readAppleFloatField(_fd);
+ _nav.startHPan = readAppleFloatField(_fd);
+ _nav.endHPan = readAppleFloatField(_fd);
+ _nav.endVPan = readAppleFloatField(_fd);
+ _nav.startVPan = readAppleFloatField(_fd);
+ _nav.initialHPan = readAppleFloatField(_fd);
+ _nav.initialVPan = readAppleFloatField(_fd);
+ _fd->readUint32BE(); // reserved2
+
+ return 0;
+}
+
int QuickTimeParser::readDREF(Atom atom) {
if (atom.size > 1) {
Track *track = _tracks.back();
diff --git a/common/formats/quicktime.h b/common/formats/quicktime.h
index b80df22dbbe..38bcd97b341 100644
--- a/common/formats/quicktime.h
+++ b/common/formats/quicktime.h
@@ -183,6 +183,32 @@ protected:
int16 nlvlTo;
};
+ enum class MovieType {
+ kStandardObject = 1,
+ kOldNavigableMovieScene,
+ kObjectInScene
+ };
+
+ struct Navigation {
+ uint16 columns;
+ uint16 rows;
+ uint16 loop_size; // Number of frames shot at each position
+ uint16 frame_duration;
+
+ MovieType movie_type;
+
+ uint16 loop_ticks; // Number of ticks before next frame of loop is displayed
+
+ float field_of_view;
+
+ float startHPan;
+ float startVPan;
+ float endHPan;
+ float endVPan;
+ float initialHPan;
+ float initialVPan;
+ };
+
virtual SampleDesc *readSampleDesc(Track *track, uint32 format, uint32 descSize) = 0;
uint32 _timeScale; // movie time
@@ -190,6 +216,7 @@ protected:
Rational _scaleFactorX;
Rational _scaleFactorY;
Array<Track *> _tracks;
+ Navigation _nav;
void init();
@@ -233,6 +260,7 @@ private:
int readWAVE(Atom atom);
int readESDS(Atom atom);
int readSMI(Atom atom);
+ int readNAVG(Atom atom);
};
/** @} */
Commit: 4a180f94f52ec984560bc646f7d7b6e85d848294
https://github.com/scummvm/scummvm/commit/4a180f94f52ec984560bc646f7d7b6e85d848294
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
COMMON: FORMATS: Implement ctyp atom parsing for QuickTime movies
This commit implements ctyp (Controller Type) atom parsing for QuickTime movies.
It identifies whether the movie is a panoramic movie or an object movie.
Changed paths:
common/formats/quicktime.cpp
common/formats/quicktime.h
diff --git a/common/formats/quicktime.cpp b/common/formats/quicktime.cpp
index 9cd40405f0c..ff22d886160 100644
--- a/common/formats/quicktime.cpp
+++ b/common/formats/quicktime.cpp
@@ -50,6 +50,7 @@ QuickTimeParser::QuickTimeParser() {
_resFork = new MacResManager();
_disposeFileHandle = DisposeAfterUse::YES;
_timeScale = 1;
+ _qtvrType = QTVRType::OTHER;
initParseTable();
}
@@ -161,6 +162,7 @@ void QuickTimeParser::initParseTable() {
{ &QuickTimeParser::readTKHD, MKTAG('t', 'k', 'h', 'd') },
{ &QuickTimeParser::readTRAK, MKTAG('t', 'r', 'a', 'k') },
{ &QuickTimeParser::readDefault, MKTAG('u', 'd', 't', 'a') },
+ { &QuickTimeParser::readCTYP, MKTAG('c', 't', 'y', 'p') },
{ &QuickTimeParser::readNAVG, MKTAG('N', 'A', 'V', 'G') },
{ &QuickTimeParser::readLeaf, MKTAG('v', 'm', 'h', 'd') },
{ &QuickTimeParser::readCMOV, MKTAG('c', 'm', 'o', 'v') },
@@ -799,6 +801,28 @@ int QuickTimeParser::readSMI(Atom atom) {
return 0;
}
+int QuickTimeParser::readCTYP(Atom atom) {
+ uint32 ctype = _fd->readUint32BE();
+
+ switch (ctype) {
+ case MKTAG('s', 't', 'n', 'a'):
+ _qtvrType = QTVRType::OBJECT;
+ break;
+
+ case MKTAG('S', 'T', 'p', 'n'):
+ case MKTAG('s', 't', 'p', 'n'):
+ _qtvrType = QTVRType::PANORAMA;
+ break;
+
+ default:
+ _qtvrType = QTVRType::OTHER;
+ warning("QuickTimeParser::readCTYP(): Unknown QTVR Type ('%s')", tag2str(ctype));
+ break;
+ }
+
+ return 0;
+}
+
static float readAppleFloatField(SeekableReadStream *stream) {
int16 a = stream->readSint16BE();
uint16 b = stream->readUint16BE();
diff --git a/common/formats/quicktime.h b/common/formats/quicktime.h
index 38bcd97b341..8c0ff0ac2f3 100644
--- a/common/formats/quicktime.h
+++ b/common/formats/quicktime.h
@@ -209,6 +209,12 @@ protected:
float initialVPan;
};
+ enum class QTVRType {
+ OTHER,
+ OBJECT,
+ PANORAMA
+ };
+
virtual SampleDesc *readSampleDesc(Track *track, uint32 format, uint32 descSize) = 0;
uint32 _timeScale; // movie time
@@ -217,6 +223,7 @@ protected:
Rational _scaleFactorY;
Array<Track *> _tracks;
Navigation _nav;
+ QTVRType _qtvrType;
void init();
@@ -260,6 +267,7 @@ private:
int readWAVE(Atom atom);
int readESDS(Atom atom);
int readSMI(Atom atom);
+ int readCTYP(Atom atom);
int readNAVG(Atom atom);
};
Commit: fc34902998022da7cb1872358a93e8efb64b9ca4
https://github.com/scummvm/scummvm/commit/fc34902998022da7cb1872358a93e8efb64b9ca4
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
COMMON: FORMATS: Implement pInf atom parsing for QuickTime movies
This commit implements pInf (Panorama Information) atom parsing for QuickTime movies.
It contains information about panoramic nodes (ID, timestamp) and the default node's zoom level.
Changed paths:
common/formats/quicktime.cpp
common/formats/quicktime.h
diff --git a/common/formats/quicktime.cpp b/common/formats/quicktime.cpp
index ff22d886160..14c44290069 100644
--- a/common/formats/quicktime.cpp
+++ b/common/formats/quicktime.cpp
@@ -171,6 +171,8 @@ void QuickTimeParser::initParseTable() {
{ &QuickTimeParser::readSMI, MKTAG('S', 'M', 'I', ' ') },
{ &QuickTimeParser::readDefault, MKTAG('g', 'm', 'h', 'd') },
{ &QuickTimeParser::readLeaf, MKTAG('g', 'm', 'i', 'n') },
+ { &QuickTimeParser::readDefault, MKTAG('S', 'T', 'p', 'n') },
+ { &QuickTimeParser::readPINF, MKTAG('p', 'I', 'n', 'f') },
{ nullptr, 0 }
};
@@ -853,6 +855,25 @@ int QuickTimeParser::readNAVG(Atom atom) {
return 0;
}
+int QuickTimeParser::readPINF(Atom atom) {
+ Track *track = _tracks.back();
+
+ track->panoInfo.name = _fd->readPascalString();
+ _fd->seek((int64)atom.offset + 32);
+ track->panoInfo.defNodeID = _fd->readUint32BE();
+ track->panoInfo.defZoom = readAppleFloatField(_fd);
+ _fd->readUint32BE(); // reserved
+ _fd->readSint16BE(); // padding
+ int16 numEntries = _fd->readSint16BE();
+ track->panoInfo.nodes.resize(numEntries);
+ for (int16 i = 0; i < numEntries; i++) {
+ track->panoInfo.nodes[i].nodeID = _fd->readUint32BE();
+ track->panoInfo.nodes[i].timestamp = _fd->readUint32BE();
+ }
+
+ return 0;
+}
+
int QuickTimeParser::readDREF(Atom atom) {
if (atom.size > 1) {
Track *track = _tracks.back();
diff --git a/common/formats/quicktime.h b/common/formats/quicktime.h
index 8c0ff0ac2f3..6ed783a447f 100644
--- a/common/formats/quicktime.h
+++ b/common/formats/quicktime.h
@@ -144,6 +144,18 @@ protected:
CODEC_TYPE_MIDI
};
+ struct PanoramaNode {
+ uint32 nodeID;
+ uint32 timestamp;
+ };
+
+ struct PanoramaInformation {
+ String name;
+ uint32 defNodeID;
+ float defZoom;
+ Array<PanoramaNode> nodes;
+ };
+
struct Track {
Track();
~Track();
@@ -181,6 +193,8 @@ protected:
Common::String directory;
int16 nlvlFrom;
int16 nlvlTo;
+
+ PanoramaInformation panoInfo;
};
enum class MovieType {
@@ -269,6 +283,7 @@ private:
int readSMI(Atom atom);
int readCTYP(Atom atom);
int readNAVG(Atom atom);
+ int readPINF(Atom atom);
};
/** @} */
Commit: d704b8e959212ca7992450f171cf804fa1902b8b
https://github.com/scummvm/scummvm/commit/d704b8e959212ca7992450f171cf804fa1902b8b
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
COMMON: FORMATS: Implement vmhd atom parsing for QuickTime movies
This commit implements vmhd (Video Media Information Header) atom parsing for QuickTime movies.
It contains information about the video track's graphics mode and opcolor.
Changed paths:
common/formats/quicktime.cpp
common/formats/quicktime.h
diff --git a/common/formats/quicktime.cpp b/common/formats/quicktime.cpp
index 14c44290069..e398c91d82b 100644
--- a/common/formats/quicktime.cpp
+++ b/common/formats/quicktime.cpp
@@ -164,7 +164,7 @@ void QuickTimeParser::initParseTable() {
{ &QuickTimeParser::readDefault, MKTAG('u', 'd', 't', 'a') },
{ &QuickTimeParser::readCTYP, MKTAG('c', 't', 'y', 'p') },
{ &QuickTimeParser::readNAVG, MKTAG('N', 'A', 'V', 'G') },
- { &QuickTimeParser::readLeaf, MKTAG('v', 'm', 'h', 'd') },
+ { &QuickTimeParser::readVMHD, MKTAG('v', 'm', 'h', 'd') },
{ &QuickTimeParser::readCMOV, MKTAG('c', 'm', 'o', 'v') },
{ &QuickTimeParser::readWAVE, MKTAG('w', 'a', 'v', 'e') },
{ &QuickTimeParser::readESDS, MKTAG('e', 's', 'd', 's') },
@@ -667,6 +667,16 @@ int QuickTimeParser::readSTTS(Atom atom) {
return 0;
}
+int QuickTimeParser::readVMHD(Atom atom) {
+ Track *track = _tracks.back();
+
+ _fd->readUint32BE(); // version + flags
+ track->graphicsMode = (GraphicsMode)_fd->readUint16BE();
+ _fd->readMultipleBE(track->opcolor);
+
+ return 0;
+}
+
int QuickTimeParser::readSTCO(Atom atom) {
Track *track = _tracks.back();
@@ -1037,6 +1047,8 @@ QuickTimeParser::Track::Track() {
mediaDuration = 0;
nlvlFrom = -1;
nlvlTo = -1;
+ graphicsMode = GraphicsMode::COPY;
+ opcolor[0] = opcolor[1] = opcolor[2] = 0;
}
QuickTimeParser::Track::~Track() {
diff --git a/common/formats/quicktime.h b/common/formats/quicktime.h
index 6ed783a447f..d5c56378576 100644
--- a/common/formats/quicktime.h
+++ b/common/formats/quicktime.h
@@ -144,6 +144,18 @@ protected:
CODEC_TYPE_MIDI
};
+ enum class GraphicsMode {
+ COPY = 0x0, // Directly copy the source image over the destination.
+ DITHER_COPY = 0x40, // Dither the image (if needed), otherwise copy.
+ BLEND = 0x20, // Blend source and destination pixel colors using opcolor values.
+ TRANSPARENT = 0x24, // Replace destination with source if not equal to opcolor.
+ STRAIGHT_ALPHA = 0x100, // Blend source and destination pixels, with the proportion controlled by the alpha channel.
+ PREMUL_WHITE_ALPHA = 0x101, // Blend after removing pre-multiplied white from the source.
+ PREMUL_BLACK_ALPHA = 0x102, // Blend after removing pre-multiplied black from the source.
+ STRAIGHT_ALPHA_BLEND = 0x104, // Similar to straight alpha, but the alpha for each channel is combined with the corresponding opcolor channel.
+ COMPOSITION = 0x103 // Render offscreen and then dither-copy to the main screen (tracks only).
+ };
+
struct PanoramaNode {
uint32 nodeID;
uint32 timestamp;
@@ -195,6 +207,9 @@ protected:
int16 nlvlTo;
PanoramaInformation panoInfo;
+
+ GraphicsMode graphicsMode; // Transfer mode
+ uint16 opcolor[3]; // RGB values used in the transfer mode specified by graphicsMode.
};
enum class MovieType {
@@ -277,6 +292,7 @@ private:
int readSTSS(Atom atom);
int readSTSZ(Atom atom);
int readSTTS(Atom atom);
+ int readVMHD(Atom atom);
int readCMOV(Atom atom);
int readWAVE(Atom atom);
int readESDS(Atom atom);
Commit: 5e6b127a8c1cd5ed2f738565aad4c6d6233aa743
https://github.com/scummvm/scummvm/commit/5e6b127a8c1cd5ed2f738565aad4c6d6233aa743
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
COMMON: FORMATS: Implement gmin atom parsing for QuickTime movies
This commit implements gmin (Base Media Info Atom) parsing for QuickTime movies.
It defines control information for the media, including graphics mode and balance.
Changed paths:
common/formats/quicktime.cpp
common/formats/quicktime.h
diff --git a/common/formats/quicktime.cpp b/common/formats/quicktime.cpp
index e398c91d82b..9e06925d604 100644
--- a/common/formats/quicktime.cpp
+++ b/common/formats/quicktime.cpp
@@ -170,7 +170,7 @@ void QuickTimeParser::initParseTable() {
{ &QuickTimeParser::readESDS, MKTAG('e', 's', 'd', 's') },
{ &QuickTimeParser::readSMI, MKTAG('S', 'M', 'I', ' ') },
{ &QuickTimeParser::readDefault, MKTAG('g', 'm', 'h', 'd') },
- { &QuickTimeParser::readLeaf, MKTAG('g', 'm', 'i', 'n') },
+ { &QuickTimeParser::readGMIN, MKTAG('g', 'm', 'i', 'n') },
{ &QuickTimeParser::readDefault, MKTAG('S', 'T', 'p', 'n') },
{ &QuickTimeParser::readPINF, MKTAG('p', 'I', 'n', 'f') },
{ nullptr, 0 }
@@ -865,6 +865,18 @@ int QuickTimeParser::readNAVG(Atom atom) {
return 0;
}
+int QuickTimeParser::readGMIN(Atom atom) {
+ Track *track = _tracks.back();
+
+ _fd->readUint32BE(); // version + flags
+ track->graphicsMode = (GraphicsMode)_fd->readUint16BE();
+ _fd->readMultipleBE(track->opcolor);
+ track->soundBalance = _fd->readUint16BE();
+ _fd->readUint16BE(); // reserved
+
+ return 0;
+}
+
int QuickTimeParser::readPINF(Atom atom) {
Track *track = _tracks.back();
@@ -1049,6 +1061,7 @@ QuickTimeParser::Track::Track() {
nlvlTo = -1;
graphicsMode = GraphicsMode::COPY;
opcolor[0] = opcolor[1] = opcolor[2] = 0;
+ soundBalance = 0;
}
QuickTimeParser::Track::~Track() {
diff --git a/common/formats/quicktime.h b/common/formats/quicktime.h
index d5c56378576..7902e50bb9d 100644
--- a/common/formats/quicktime.h
+++ b/common/formats/quicktime.h
@@ -210,6 +210,8 @@ protected:
GraphicsMode graphicsMode; // Transfer mode
uint16 opcolor[3]; // RGB values used in the transfer mode specified by graphicsMode.
+
+ uint16 soundBalance; // Controls the sound mix between the computer's two speakers, usually set to 0.
};
enum class MovieType {
@@ -299,6 +301,7 @@ private:
int readSMI(Atom atom);
int readCTYP(Atom atom);
int readNAVG(Atom atom);
+ int readGMIN(Atom atom);
int readPINF(Atom atom);
};
Commit: 5d0c7457839474e6e44e54e505e576c8bc8239e2
https://github.com/scummvm/scummvm/commit/5d0c7457839474e6e44e54e505e576c8bc8239e2
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
COMMON: FORMATS: Implement WLOC atom parsing for QuickTime movies
This commit implements WLOC (Window Location) atom parsing for QuickTime movies.
It defines the default window location for the movie.
Changed paths:
common/formats/quicktime.cpp
common/formats/quicktime.h
diff --git a/common/formats/quicktime.cpp b/common/formats/quicktime.cpp
index 9e06925d604..35b70aa9c70 100644
--- a/common/formats/quicktime.cpp
+++ b/common/formats/quicktime.cpp
@@ -51,6 +51,8 @@ QuickTimeParser::QuickTimeParser() {
_disposeFileHandle = DisposeAfterUse::YES;
_timeScale = 1;
_qtvrType = QTVRType::OTHER;
+ _winX = 0;
+ _winY = 0;
initParseTable();
}
@@ -163,6 +165,7 @@ void QuickTimeParser::initParseTable() {
{ &QuickTimeParser::readTRAK, MKTAG('t', 'r', 'a', 'k') },
{ &QuickTimeParser::readDefault, MKTAG('u', 'd', 't', 'a') },
{ &QuickTimeParser::readCTYP, MKTAG('c', 't', 'y', 'p') },
+ { &QuickTimeParser::readWLOC, MKTAG('W', 'L', 'O', 'C') },
{ &QuickTimeParser::readNAVG, MKTAG('N', 'A', 'V', 'G') },
{ &QuickTimeParser::readVMHD, MKTAG('v', 'm', 'h', 'd') },
{ &QuickTimeParser::readCMOV, MKTAG('c', 'm', 'o', 'v') },
@@ -835,6 +838,13 @@ int QuickTimeParser::readCTYP(Atom atom) {
return 0;
}
+int QuickTimeParser::readWLOC(Atom atom) {
+ _winX = _fd->readUint16BE();
+ _winY = _fd->readUint16BE();
+
+ return 0;
+}
+
static float readAppleFloatField(SeekableReadStream *stream) {
int16 a = stream->readSint16BE();
uint16 b = stream->readUint16BE();
diff --git a/common/formats/quicktime.h b/common/formats/quicktime.h
index 7902e50bb9d..cae9cf3ee61 100644
--- a/common/formats/quicktime.h
+++ b/common/formats/quicktime.h
@@ -255,6 +255,8 @@ protected:
Array<Track *> _tracks;
Navigation _nav;
QTVRType _qtvrType;
+ uint16 _winX;
+ uint16 _winY;
void init();
@@ -300,6 +302,7 @@ private:
int readESDS(Atom atom);
int readSMI(Atom atom);
int readCTYP(Atom atom);
+ int readWLOC(Atom atom);
int readNAVG(Atom atom);
int readGMIN(Atom atom);
int readPINF(Atom atom);
Commit: 9596bf04a8183ec829a9c497732e943211706560
https://github.com/scummvm/scummvm/commit/9596bf04a8183ec829a9c497732e943211706560
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
COMMON: FORMATS: Implement smhd atom parsing for QuickTime movies
This commit implements smhd (Sound Media Information Header Atom) parsing for QuickTime movies.
It defines the sound mediaâs control information, such as balance.
Changed paths:
common/formats/quicktime.cpp
common/formats/quicktime.h
diff --git a/common/formats/quicktime.cpp b/common/formats/quicktime.cpp
index 35b70aa9c70..91f0212eb0b 100644
--- a/common/formats/quicktime.cpp
+++ b/common/formats/quicktime.cpp
@@ -153,7 +153,7 @@ void QuickTimeParser::initParseTable() {
{ &QuickTimeParser::readDefault, MKTAG('m', 'i', 'n', 'f') },
{ &QuickTimeParser::readMOOV, MKTAG('m', 'o', 'o', 'v') },
{ &QuickTimeParser::readMVHD, MKTAG('m', 'v', 'h', 'd') },
- { &QuickTimeParser::readLeaf, MKTAG('s', 'm', 'h', 'd') },
+ { &QuickTimeParser::readSMHD, MKTAG('s', 'm', 'h', 'd') },
{ &QuickTimeParser::readDefault, MKTAG('s', 't', 'b', 'l') },
{ &QuickTimeParser::readSTCO, MKTAG('s', 't', 'c', 'o') },
{ &QuickTimeParser::readSTSC, MKTAG('s', 't', 's', 'c') },
@@ -384,6 +384,16 @@ int QuickTimeParser::readTRAK(Atom atom) {
return readDefault(atom);
}
+int QuickTimeParser::readSMHD(Atom atom) {
+ Track *track = _tracks.back();
+
+ _fd->readUint32BE(); // version + flags
+ track->soundBalance = _fd->readUint16BE();
+ _fd->readUint16BE(); // reserved
+
+ return 0;
+}
+
int QuickTimeParser::readTKHD(Atom atom) {
Track *track = _tracks.back();
byte version = _fd->readByte();
diff --git a/common/formats/quicktime.h b/common/formats/quicktime.h
index cae9cf3ee61..0301b38d1c7 100644
--- a/common/formats/quicktime.h
+++ b/common/formats/quicktime.h
@@ -290,6 +290,7 @@ private:
int readMVHD(Atom atom);
int readTKHD(Atom atom);
int readTRAK(Atom atom);
+ int readSMHD(Atom atom);
int readSTCO(Atom atom);
int readSTSC(Atom atom);
int readSTSD(Atom atom);
Commit: e4624cf95bc647057992212dc6e7de5ef639c1c0
https://github.com/scummvm/scummvm/commit/e4624cf95bc647057992212dc6e7de5ef639c1c0
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
COMMON: Implement interactive control for QuickTime object movies
This commmit implements interactive mouse control for QuickTime object movies.
Changed paths:
video/qt_decoder.cpp
video/qt_decoder.h
video/video_decoder.h
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 2aece4ce535..fce37e8c3d1 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -51,6 +51,9 @@ QuickTimeDecoder::QuickTimeDecoder() {
_scaledSurface = 0;
_width = _height = 0;
_enableEditListBoundsCheckQuirk = false;
+ _prevMouseX = _prevMouseY = 0;
+ _isMouseButtonDown = false;
+ _isVR = false;
}
QuickTimeDecoder::~QuickTimeDecoder() {
@@ -211,6 +214,9 @@ Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Common::Qu
}
void QuickTimeDecoder::init() {
+ if (_qtvrType == QTVRType::OBJECT || _qtvrType == QTVRType::PANORAMA)
+ _isVR = true;
+
Audio::QuickTimeAudioDecoder::init();
// Initialize all the audio tracks
@@ -301,6 +307,8 @@ QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder
_curFrame = -1;
_delayedFrameToBufferTo = -1;
enterNewEditListEntry(true, true); // might set _curFrame
+ if (decoder->_qtvrType == QTVRType::OBJECT)
+ _curFrame = getFrameCount() / 2;
_durationOverride = -1;
_scaledSurface = 0;
@@ -366,7 +374,10 @@ QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() {
bool QuickTimeDecoder::VideoTrackHandler::endOfTrack() const {
// A track is over when we've finished going through all edits
- return _reversed ? (_curEdit == 0 && _curFrame < 0) : atLastEdit();
+ if (!_decoder->_isVR)
+ return _reversed ? (_curEdit == 0 && _curFrame < 0) : atLastEdit();
+ else
+ return false;
}
bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requestedTime) {
@@ -473,7 +484,7 @@ int QuickTimeDecoder::VideoTrackHandler::getFrameCount() const {
}
uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() const {
- if (endOfTrack())
+ if (endOfTrack() || _decoder->_isVR)
return 0;
Audio::Timestamp frameTime(0, getRateAdjustedFrameTime(), _parent->timeScale);
@@ -577,6 +588,59 @@ Common::String QuickTimeDecoder::getAliasPath() {
return Common::String();
}
+void QuickTimeDecoder::handleMouseMove(int16 x, int16 y) {
+ if (_qtvrType != QTVRType::OBJECT || !_isMouseButtonDown )
+ return;
+
+ VideoTrackHandler *track = (VideoTrackHandler *)_nextVideoTrack;
+
+ // HACK: FIXME: Hard coded for now
+ const int sensitivity = 10;
+ const float speedFactor = 0.1f;
+
+ int16 mouseDeltaX = x - _prevMouseX;
+ int16 mouseDeltaY = y - _prevMouseY;
+
+ float speedX = (float)mouseDeltaX * speedFactor;
+ float speedY = (float)mouseDeltaY * speedFactor;
+
+ bool changed = false;
+
+ if (ABS(mouseDeltaY) >= sensitivity) {
+ int newFrame = track->getCurFrame() - round(speedY) * _nav.columns;
+
+ if (newFrame >= 0 && newFrame < track->getFrameCount())
+ track->setCurFrame(newFrame);
+
+ changed = true;
+ }
+
+ if (ABS(mouseDeltaX) >= sensitivity) {
+ int currentRow = track->getCurFrame() / _nav.columns;
+ int currentRowStart = currentRow * _nav.columns;
+
+ int newFrame = (track->getCurFrame() - (int)roundf(speedX) - currentRowStart) % _nav.columns + currentRowStart;
+
+ track->setCurFrame(newFrame);
+
+ changed = true;
+ }
+
+ if (changed) {
+ _prevMouseX = x;
+ _prevMouseY = y;
+ }
+}
+
+void QuickTimeDecoder::handleMouseButton(bool isDown, int16 x, int16 y) {
+ _isMouseButtonDown = isDown;
+
+ if (isDown) {
+ _prevMouseX = x;
+ _prevMouseY = y;
+ }
+}
+
Audio::Timestamp QuickTimeDecoder::VideoTrackHandler::getFrameTime(uint frame) const {
// TODO: This probably doesn't work right with edit lists
int cumulativeDuration = 0;
@@ -815,7 +879,8 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::bufferNextFrame()
}
}
- _curFrame++;
+ if (!_decoder->_isVR)
+ _curFrame++;
// Get the next packet
uint32 descId;
@@ -901,7 +966,10 @@ bool QuickTimeDecoder::VideoTrackHandler::atLastEdit() const {
bool QuickTimeDecoder::VideoTrackHandler::endOfCurEdit() const {
// We're at the end of the edit once the next frame's time would
// bring us past the end of the edit.
- return getRateAdjustedFrameTime() >= getCurEditTimeOffset() + getCurEditTrackDuration();
+ if (!_decoder->_isVR)
+ return getRateAdjustedFrameTime() >= getCurEditTimeOffset() + getCurEditTrackDuration();
+ else
+ return false;
}
bool QuickTimeDecoder::VideoTrackHandler::canDither() const {
diff --git a/video/qt_decoder.h b/video/qt_decoder.h
index 207bfb0428f..ae0e839e241 100644
--- a/video/qt_decoder.h
+++ b/video/qt_decoder.h
@@ -73,6 +73,11 @@ public:
void enableEditListBoundsCheckQuirk(bool enable) { _enableEditListBoundsCheckQuirk = enable; }
Common::String getAliasPath();
+ void handleMouseMove(int16 x, int16 y);
+ void handleMouseButton(bool isDown, int16 x = -1, int16 y = -1);
+
+ bool isVR() const { return _isVR; }
+
protected:
Common::QuickTimeParser::SampleDesc *readSampleDesc(Common::QuickTimeParser::Track *track, uint32 format, uint32 descSize);
@@ -83,6 +88,11 @@ private:
uint16 _width, _height;
+ uint16 _prevMouseX, _prevMouseY;
+ bool _isMouseButtonDown;
+
+ bool _isVR;
+
Graphics::Surface *_scaledSurface;
void scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst,
const Common::Rational &scaleFactorX, const Common::Rational &scaleFactorY);
@@ -138,6 +148,7 @@ private:
Graphics::PixelFormat getPixelFormat() const;
bool setOutputPixelFormat(const Graphics::PixelFormat &format);
int getCurFrame() const { return _curFrame; }
+ void setCurFrame(int32 curFrame) { _curFrame = curFrame; }
int getFrameCount() const;
uint32 getNextFrameStartTime() const; // milliseconds
const Graphics::Surface *decodeNextFrame();
diff --git a/video/video_decoder.h b/video/video_decoder.h
index 3818159d0d6..9d07f92968e 100644
--- a/video/video_decoder.h
+++ b/video/video_decoder.h
@@ -974,7 +974,6 @@ private:
Audio::Timestamp _endTime;
bool _endTimeSet;
Common::Rational _playbackRate;
- VideoTrack *_nextVideoTrack;
// Palette settings from individual tracks
mutable bool _dirtyPalette;
@@ -996,6 +995,8 @@ protected:
Audio::Timestamp _lastTimeChange;
int32 _startTime;
+ VideoTrack *_nextVideoTrack;
+
private:
uint32 _pauseLevel;
uint32 _pauseStartTime;
Commit: 01c2def79537121708a65d104ae05e15c4cae22e
https://github.com/scummvm/scummvm/commit/01c2def79537121708a65d104ae05e15c4cae22e
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
TESTBED: Enable mouse event handling for QuickTime interactivity
Changed paths:
engines/testbed/video.cpp
diff --git a/engines/testbed/video.cpp b/engines/testbed/video.cpp
index c9fd79ae714..d2563c60ecd 100644
--- a/engines/testbed/video.cpp
+++ b/engines/testbed/video.cpp
@@ -134,6 +134,20 @@ Common::Error Videotests::videoTest(Common::SeekableReadStream *stream, const Co
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_LBUTTONDOWN:
+ ((Video::QuickTimeDecoder *)video)->handleMouseButton(true, event.mouse.x, event.mouse.y);
+ break;
+ case Common::EVENT_LBUTTONUP:
+ ((Video::QuickTimeDecoder *)video)->handleMouseButton(false);
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ ((Video::QuickTimeDecoder *)video)->handleMouseMove(event.mouse.x, event.mouse.y);
+ break;
+ default:
+ break;
+ }
+
if (Engine::shouldQuit()) {
video->close();
delete video;
Commit: c39c63af3ae87835ba8176088c63369db1d5947e
https://github.com/scummvm/scummvm/commit/c39c63af3ae87835ba8176088c63369db1d5947e
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
COMMON: FORMATS: Add support for parsing QuickTime VR panorama atoms
This commit introduces functionality to parse panorama atoms in QuickTime VR files.
Atoms parsed include:
- pHdr: PanoSampleHeader
- pHot: HotSpotTableAtom
- strT: StringTableAtom
- pLnk: LinkTableAtom
- pNav: NavgTableAtom
Changed paths:
common/formats/quicktime.cpp
common/formats/quicktime.h
diff --git a/common/formats/quicktime.cpp b/common/formats/quicktime.cpp
index 91f0212eb0b..53089afe5f1 100644
--- a/common/formats/quicktime.cpp
+++ b/common/formats/quicktime.cpp
@@ -53,6 +53,7 @@ QuickTimeParser::QuickTimeParser() {
_qtvrType = QTVRType::OTHER;
_winX = 0;
_winY = 0;
+ _panoTrack = nullptr;
initParseTable();
}
@@ -95,6 +96,11 @@ bool QuickTimeParser::parseFile(const Path &filename) {
if (readDefault(atom) < 0 || !_foundMOOV)
return false;
+ if (_qtvrType == QTVRType::PANORAMA) {
+ if (!parsePanoramaAtoms())
+ return false;
+ }
+
init();
return true;
}
@@ -111,10 +117,49 @@ bool QuickTimeParser::parseStream(SeekableReadStream *stream, DisposeAfterUse::F
return false;
}
+ if (_qtvrType == QTVRType::PANORAMA) {
+ if (!parsePanoramaAtoms())
+ return false;
+ }
+
init();
return true;
}
+bool QuickTimeParser::parsePanoramaAtoms() {
+ for (uint i = 0; i < _tracks.size(); i++) {
+ if (_tracks[i]->codecType == CODEC_TYPE_PANO) {
+ _panoTrack = _tracks[i];
+ break;
+ }
+ }
+
+ if (!_panoTrack) {
+ warning("QuickTimeParser::parsePanoramaAtoms(): No panoramic track found");
+ return false;
+ }
+
+ Array<uint32> sizes;
+
+ if (_panoTrack->sampleSize) {
+ sizes = { _panoTrack->sampleSize };
+ } else {
+ sizes.resize(_panoTrack->sampleCount);
+ for (uint32 i = 0; i < _panoTrack->sampleCount; i++)
+ sizes[i] = _panoTrack->sampleSizes[i];
+ }
+
+ for (uint32 i = 0; i < sizes.size() && i < _panoTrack->chunkCount; i++) {
+ _panoTrack->panoSamples.resize(_panoTrack->panoSamples.size() + 1);
+ Atom atom = { 0, _panoTrack->chunkOffsets[i], sizes[i] };
+ _fd->seek(_panoTrack->chunkOffsets[i], SEEK_SET);
+ if (readDefault(atom) < 0)
+ return false;
+ }
+
+ return true;
+}
+
void QuickTimeParser::init() {
for (uint32 i = 0; i < _tracks.size(); i++) {
// Remove unknown/unhandled tracks
@@ -176,6 +221,12 @@ void QuickTimeParser::initParseTable() {
{ &QuickTimeParser::readGMIN, MKTAG('g', 'm', 'i', 'n') },
{ &QuickTimeParser::readDefault, MKTAG('S', 'T', 'p', 'n') },
{ &QuickTimeParser::readPINF, MKTAG('p', 'I', 'n', 'f') },
+ { &QuickTimeParser::readDefault, MKTAG('S', 'T', 'p', 'n') },
+ { &QuickTimeParser::readPHDR, MKTAG('p', 'H', 'd', 'r') },
+ { &QuickTimeParser::readPHOT, MKTAG('p', 'H', 'o', 't') },
+ { &QuickTimeParser::readSTRT, MKTAG('s', 't', 'r', 'T') },
+ { &QuickTimeParser::readPLNK, MKTAG('p', 'L', 'n', 'k') },
+ { &QuickTimeParser::readPNAV, MKTAG('p', 'N', 'a', 'v') },
{ nullptr, 0 }
};
@@ -497,6 +548,8 @@ int QuickTimeParser::readHDLR(Atom atom) {
track->codecType = CODEC_TYPE_AUDIO;
else if (type == MKTAG('m', 'u', 's', 'i'))
track->codecType = CODEC_TYPE_MIDI;
+ else if (type == MKTAG('S', 'T', 'p', 'n') || type == MKTAG('s', 't', 'p', 'n'))
+ track->codecType = CODEC_TYPE_PANO;
_fd->readUint32BE(); // component manufacture
_fd->readUint32BE(); // component flags
@@ -986,6 +1039,151 @@ int QuickTimeParser::readDREF(Atom atom) {
return 0;
}
+int QuickTimeParser::readPHDR(Atom atom) {
+ PanoSampleHeader &pHdr = _panoTrack->panoSamples.back().hdr;
+
+ pHdr.nodeID = _fd->readUint32BE();
+
+ pHdr.defHPan = readAppleFloatField(_fd);
+ pHdr.defVPan = readAppleFloatField(_fd);
+ pHdr.defZoom = readAppleFloatField(_fd);
+
+ pHdr.minHPan = readAppleFloatField(_fd);
+ pHdr.minVPan = readAppleFloatField(_fd);
+ pHdr.minZoom = readAppleFloatField(_fd);
+ pHdr.maxHPan = readAppleFloatField(_fd);
+ pHdr.maxVPan = readAppleFloatField(_fd);
+ pHdr.minHPan = readAppleFloatField(_fd);
+
+ _fd->readSint64BE(); // reserved1 + reserved2
+
+ pHdr.nameStrOffset = _fd->readSint32BE();
+ pHdr.commentStrOffset = _fd->readSint32BE();
+
+ return 0;
+}
+
+int QuickTimeParser::readPHOT(Atom atom) {
+ PanoHotSpotTable &pHotSpotTable = _panoTrack->panoSamples.back().hotSpotTable;
+
+ _fd->readUint16BE(); // padding
+
+ int16 numHotSpots = _fd->readSint16BE();
+ pHotSpotTable.hotSpots.resize(numHotSpots);
+
+ for (int i = 0; i < numHotSpots; i++) {
+ pHotSpotTable.hotSpots[i].id = _fd->readUint16BE();
+
+ _fd->readUint16BE(); // reserved
+
+ uint32 type = _fd->readUint32BE();
+
+ switch (type) {
+ case MKTAG('l', 'i', 'n', 'k'):
+ pHotSpotTable.hotSpots[i].type = HotSpotType::link;
+ break;
+
+ case MKTAG('n', 'a', 'v', 'g'):
+ pHotSpotTable.hotSpots[i].type = HotSpotType::navg;
+ break;
+
+ default:
+ pHotSpotTable.hotSpots[i].type = HotSpotType::undefined;
+ warning("QuickTimeParser::readPHOT(): Unknown HotSpot Type ('%s')", tag2str(type));
+ break;
+ }
+
+ pHotSpotTable.hotSpots[i].typeData = _fd->readUint32BE();
+
+ pHotSpotTable.hotSpots[i].viewHPan = readAppleFloatField(_fd);
+ pHotSpotTable.hotSpots[i].viewVPan = readAppleFloatField(_fd);
+ pHotSpotTable.hotSpots[i].viewZoom = readAppleFloatField(_fd);
+
+ pHotSpotTable.hotSpots[i].rect.top = _fd->readSint16BE();
+ pHotSpotTable.hotSpots[i].rect.left = _fd->readSint16BE();
+ pHotSpotTable.hotSpots[i].rect.bottom = _fd->readSint16BE();
+ pHotSpotTable.hotSpots[i].rect.right = _fd->readSint16BE();
+
+ pHotSpotTable.hotSpots[i].mouseOverCursorID = _fd->readSint32BE();
+ pHotSpotTable.hotSpots[i].mouseDownCursorID = _fd->readSint32BE();
+ pHotSpotTable.hotSpots[i].mouseUpCursorID = _fd->readSint32BE();
+
+ _fd->readSint32BE(); // reserved2
+
+ pHotSpotTable.hotSpots[i].nameStrOffset = _fd->readSint32BE();
+ pHotSpotTable.hotSpots[i].commentStrOffset = _fd->readSint32BE();
+ }
+
+ return 0;
+}
+
+int QuickTimeParser::readSTRT(Atom atom) {
+ PanoStringTable &pStrTable = _panoTrack->panoSamples.back().strTable;
+
+ pStrTable.strings = _fd->readString(0, atom.size);
+
+ return 0;
+}
+
+int QuickTimeParser::readPLNK(Atom atom) {
+ PanoLinkTable &pLinkTable = _panoTrack->panoSamples.back().linkTable;
+
+ _fd->readUint16BE(); // padding
+
+ int16 numLinks = _fd->readSint16BE();
+ pLinkTable.links.resize(numLinks);
+
+ for (int i = 0; i < numLinks; i++) {
+ pLinkTable.links[i].id = _fd->readUint16BE();
+
+ _fd->readUint16BE(); // reserved
+ _fd->readUint64BE(); // reserved2 + reserved3
+
+ pLinkTable.links[i].toNodeID = _fd->readUint32BE();
+
+ _fd->skip(12); // reserved4
+
+ pLinkTable.links[i].toHPan = readAppleFloatField(_fd);
+ pLinkTable.links[i].toVPan = readAppleFloatField(_fd);
+ pLinkTable.links[i].toZoom = readAppleFloatField(_fd);
+
+ _fd->readUint64BE(); // reserved5 + reserved6
+
+ pLinkTable.links[i].nameStrOffset = _fd->readSint32BE();
+ pLinkTable.links[i].commentStrOffset = _fd->readSint32BE();
+ }
+
+ return 0;
+}
+
+int QuickTimeParser::readPNAV(Atom atom) {
+ PanoNavigationTable &pLinkTable = _panoTrack->panoSamples.back().navTable;
+
+ _fd->readUint16BE(); // padding
+
+ int16 numNavs = _fd->readSint16BE();
+ pLinkTable.navs.resize(numNavs);
+
+ for (int i = 0; i < numNavs; i++) {
+ pLinkTable.navs[i].id = _fd->readUint16BE();
+
+ _fd->readUint16BE(); // reserved
+ _fd->readUint32BE(); // reserved2
+
+ pLinkTable.navs[i].rect.top = _fd->readSint16BE();
+ pLinkTable.navs[i].rect.left = _fd->readSint16BE();
+ pLinkTable.navs[i].rect.bottom = _fd->readSint16BE();
+ pLinkTable.navs[i].rect.right = _fd->readSint16BE();
+
+ _fd->readSint32BE(); // reserved3
+
+ pLinkTable.navs[i].nameStrOffset = _fd->readSint32BE();
+ pLinkTable.navs[i].commentStrOffset = _fd->readSint32BE();
+ }
+
+ return 0;
+}
+
void QuickTimeParser::close() {
for (uint32 i = 0; i < _tracks.size(); i++)
delete _tracks[i];
@@ -1084,6 +1282,18 @@ QuickTimeParser::Track::Track() {
soundBalance = 0;
}
+String QuickTimeParser::PanoStringTable::getString(int32 offset) const {
+ offset -= 8;
+
+ if (offset < 0)
+ return String();
+
+ int32_t str_start = offset + 1;
+ int32_t str_length = strings[offset];
+
+ return strings.substr(str_start, str_length);
+}
+
QuickTimeParser::Track::~Track() {
delete[] chunkOffsets;
delete[] timeToSample;
diff --git a/common/formats/quicktime.h b/common/formats/quicktime.h
index 0301b38d1c7..03afae9d98e 100644
--- a/common/formats/quicktime.h
+++ b/common/formats/quicktime.h
@@ -36,6 +36,7 @@
#include "common/stream.h"
#include "common/rational.h"
#include "common/types.h"
+#include "common/rect.h"
namespace Common {
class MacResManager;
@@ -141,7 +142,8 @@ protected:
CODEC_TYPE_MOV_OTHER,
CODEC_TYPE_VIDEO,
CODEC_TYPE_AUDIO,
- CODEC_TYPE_MIDI
+ CODEC_TYPE_MIDI,
+ CODEC_TYPE_PANO
};
enum class GraphicsMode {
@@ -168,6 +170,103 @@ protected:
Array<PanoramaNode> nodes;
};
+ struct PanoSampleHeader {
+ uint32 nodeID;
+
+ float defHPan;
+ float defVPan;
+ float defZoom;
+
+ // Constraints for this node; zero for default
+ float minHPan;
+ float minVPan;
+ float maxHPan;
+ float maxVPan;
+ float minZoom;
+
+ int32 nameStrOffset;
+ int32 commentStrOffset;
+ };
+
+ enum class HotSpotType {
+ undefined,
+ link,
+ navg
+ };
+
+ struct PanoHotSpot {
+ uint16 id;
+ HotSpotType type;
+ uint32 typeData; // for link and navg, the ID in the link and navg table
+
+ // Canonical view for this hotspot
+ float viewHPan;
+ float viewVPan;
+ float viewZoom;
+
+ Rect rect;
+
+ int32 mouseOverCursorID;
+ int32 mouseDownCursorID;
+ int32 mouseUpCursorID;
+
+ int32 nameStrOffset;
+ int32 commentStrOffset;
+ };
+
+ struct PanoHotSpotTable {
+ Array<PanoHotSpot> hotSpots;
+ };
+
+ struct PanoStringTable {
+ String strings;
+
+ String getString(int32 offset) const;
+ };
+
+ struct PanoLink {
+ uint16 id;
+ uint16 toNodeID;
+
+ // Values to set at the destination node
+ float toHPan;
+ float toVPan;
+ float toZoom;
+
+ int32 nameStrOffset;
+ int32 commentStrOffset;
+ };
+
+ struct PanoLinkTable {
+ Array<PanoLink> links;
+ };
+
+ struct PanoNavigation {
+ uint16 id;
+
+ uint32 hPan;
+ uint32 vPan;
+ uint32 zoom;
+
+ Rect rect; // Starting rect for zoom out transitions
+
+ // Values to set at the destination node
+ int32 nameStrOffset;
+ int32 commentStrOffset;
+ };
+
+ struct PanoNavigationTable {
+ Array<PanoNavigation> navs;
+ };
+
+ struct PanoTrackSample {
+ PanoSampleHeader hdr;
+ PanoHotSpotTable hotSpotTable;
+ PanoStringTable strTable;
+ PanoLinkTable linkTable;
+ PanoNavigationTable navTable;
+ };
+
struct Track {
Track();
~Track();
@@ -207,6 +306,7 @@ protected:
int16 nlvlTo;
PanoramaInformation panoInfo;
+ Array<PanoTrackSample> panoSamples;
GraphicsMode graphicsMode; // Transfer mode
uint16 opcolor[3]; // RGB values used in the transfer mode specified by graphicsMode.
@@ -278,8 +378,12 @@ private:
MacResManager *_resFork;
bool _foundMOOV;
+ Track *_panoTrack;
+
void initParseTable();
+ bool parsePanoramaAtoms();
+
int readDefault(Atom atom);
int readLeaf(Atom atom);
int readDREF(Atom atom);
@@ -307,6 +411,12 @@ private:
int readNAVG(Atom atom);
int readGMIN(Atom atom);
int readPINF(Atom atom);
+
+ int readPHDR(Atom atom);
+ int readPHOT(Atom atom);
+ int readSTRT(Atom atom);
+ int readPLNK(Atom atom);
+ int readPNAV(Atom atom);
};
/** @} */
Commit: 00a5c879346e0d347ecf32e26ea9a28d9218a75a
https://github.com/scummvm/scummvm/commit/00a5c879346e0d347ecf32e26ea9a28d9218a75a
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-06-30T20:43:49+02:00
Commit Message:
VIDEO: Implement rendering of panorama movie in QuickTime (WIP)
This commit implements QuickTime panorama movie rendering.
The functionality does not meet expectations; further changes are required.
Reference: https://patentimages.storage.googleapis.com/74/82/23/744b4091f6a2c0/US5396583.pdf
Changed paths:
video/qt_decoder.cpp
video/qt_decoder.h
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index fce37e8c3d1..1168f45f74c 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -318,6 +318,13 @@ QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder
_forcedDitherPalette = 0;
_ditherTable = 0;
_ditherFrame = 0;
+ _isPanoConstructed = false;
+
+ _constructedPano = nullptr;
+ _projectedPano = nullptr;
+
+ if (decoder->_qtvrType == QTVRType::PANORAMA)
+ constructPanorama();
}
// FIXME: This check breaks valid QuickTime movies, such as the KQ6 Mac opening.
@@ -370,6 +377,16 @@ QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() {
_ditherFrame->free();
delete _ditherFrame;
}
+
+ if (_isPanoConstructed) {
+ _constructedPano->free();
+ delete _constructedPano;
+ }
+
+ if (_projectedPano) {
+ _projectedPano->free();
+ delete _projectedPano;
+ }
}
bool QuickTimeDecoder::VideoTrackHandler::endOfTrack() const {
@@ -506,6 +523,19 @@ uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() const {
}
const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() {
+ if (_decoder->_qtvrType == QTVRType::PANORAMA) {
+ if (!_isPanoConstructed)
+ return nullptr;
+
+ if (_projectedPano) {
+ _projectedPano->free();
+ delete _projectedPano;
+ }
+
+ projectPanorama();
+ return _projectedPano;
+ }
+
if (endOfTrack())
return 0;
@@ -879,7 +909,7 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::bufferNextFrame()
}
}
- if (!_decoder->_isVR)
+ if (_decoder->_qtvrType != QTVRType::OBJECT)
_curFrame++;
// Get the next packet
@@ -1042,6 +1072,65 @@ void ditherFrame(const Graphics::Surface &src, Graphics::Surface &dst, const byt
} // End of anonymous namespace
+void QuickTimeDecoder::VideoTrackHandler::constructPanorama() {
+ int16 totalWidth = getHeight() * _parent->frameCount;
+ int16 totalHeight = getWidth();
+
+ if (totalWidth <= 0 || totalHeight <= 0)
+ return;
+
+ _constructedPano = new Graphics::Surface();
+ _constructedPano->create(totalWidth, totalHeight, getPixelFormat());
+
+ for (uint32 frameIndex = 0; frameIndex < _parent->frameCount; frameIndex++) {
+ const Graphics::Surface *frame = bufferNextFrame();
+
+ for (int16 y = 0; y < frame->h; y++) {
+ for (int16 x = 0; x < frame->w; x++) {
+
+ int setX = (totalWidth - 1) - (frameIndex * _parent->height + y);
+ int setY = x;
+
+ if (setX >= 0 && setX < _constructedPano->w && setY >= 0 && setY < _constructedPano->h) {
+ uint32 pixel = frame->getPixel(x, y);
+ _constructedPano->setPixel(setX, setY, pixel);
+ }
+ }
+ }
+ }
+
+ _isPanoConstructed = true;
+}
+
+void QuickTimeDecoder::VideoTrackHandler::projectPanorama() {
+ if (!_isPanoConstructed)
+ return;
+
+ _projectedPano = new Graphics::Surface();
+ _projectedPano->create(_constructedPano->w, _constructedPano->h, _constructedPano->format);
+
+ const float c = _projectedPano->w;
+ const float r = c / (2 * M_PI);
+
+ // HACK: FIXME: Hard coded for now
+ const float d = 500.0f;
+
+ for (int16 y = 0; y < _projectedPano->h; y++) {
+ for (int16 x = 0; x < _projectedPano->w; x++) {
+ double u = atan(x / d) / (2.0 * M_PI);
+ double v = y * r * cos(u) / d;
+
+ int setX = round(u * _constructedPano->w);
+ int setY = round(v);
+
+ if (setX >= 0 && setX < _constructedPano->w && setY >= 0 && setY < _constructedPano->h) {
+ uint32 pixel = _constructedPano->getPixel(setX, setY);
+ _projectedPano->setPixel(x, y, pixel);
+ }
+ }
+ }
+}
+
const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::forceDither(const Graphics::Surface &frame) {
if (frame.format.bytesPerPixel == 1) {
// This should always be true, but this is for sanity
diff --git a/video/qt_decoder.h b/video/qt_decoder.h
index ae0e839e241..32990e66eed 100644
--- a/video/qt_decoder.h
+++ b/video/qt_decoder.h
@@ -176,6 +176,14 @@ private:
mutable bool _dirtyPalette;
bool _reversed;
+ void constructPanorama();
+ void projectPanorama();
+
+ Graphics::Surface *_constructedPano;
+ Graphics::Surface *_projectedPano;
+
+ bool _isPanoConstructed;
+
// Forced dithering of frames
byte *_forcedDitherPalette;
byte *_ditherTable;
More information about the Scummvm-git-logs
mailing list