Skip to content

Commit

Permalink
Merge pull request #118 from jrdennisoss/issue-117
Browse files Browse the repository at this point in the history
Drive "magic" MPEG video correction from "magic keys" provided by the emulated game.
  • Loading branch information
jrdennisoss committed Apr 19, 2022
2 parents 26e1cb3 + 3bfa96b commit 0cb2f83
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 29 deletions.
19 changes: 11 additions & 8 deletions NOTES_MPEG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,23 @@ Facts:

* Can the `f_code` update per picture as with standard MPEG-1 video, or is it limited to one static forward/backward static value pair per MPEG file/sequence?
* What is the exact relationship between temporal sequence number and `f_code`?
* How exactly does the `driver_call(9, X, 0208h, ...)` (aka. "Magic Key") call directly impact this?

## Current Emulator Workaround

A truthful `f_code` value appears to be in all P and B pictures with a temporal
sequence number of either 3 or 8, so I am currently seeking to the first P or B
picture header matching these criteria, and applying a static `f_code`
value to all forward and backward motion vector `f_code` values for
magical MPEG files.

For picture headers containing empty "user data", I use 4 as the truthful
temporal sequence number. (The Horde)
The emulator takes uses `driver_call(9, X, 0208h, ...)` (aka "Set Magic Key") to determine where to find a
truthful `f_code` value which gets applied to the entire MPEG asset when a "magical" `picture_rate` code
is specified. The MPEG asset file is quickly scrubbed at media handle open time to find a matchiing P or B
picture containing a truthful `f_code` value. Then this value is statically applied to the entire decoding
of said MPEG asset file.

Eventually, I think this needs to be handled on a per-picture basis.

Known "magic key" values:

* 0x40044041 -- Default value. Truthful `f_code` found in temporal sequence number of 3 or 8.
* 0xC39D7088 -- Used in The Horde. Truthful `f_code` found in temporal sequence number of 4.


## Analyzing and Inspecting These Files

Expand Down
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,13 @@ configure anything to have a working ReelMagic setup as the defaults will
enable ReelMagic emulation.
The parameters are:

* `enabled` -- Enables/disables the ReelMagic emulator. By default this is `true`
* `alwaysresident` -- This forces `FMPDRV.EXE` to always be loaded. By default this is `false`
* `vgadup5hack` -- Duplicate every 5th VGA line to help give output a 4:3 ratio. By default this is `false`
* `magicfhack` -- Use for MPEG video debugging purposes only. See `reelmagic_player.cpp` for what exactly this does to the MPEG decoder.
* `a204debug` -- Controls FMPDRV.EXE function Ah subfunction 204h debug logging. Only applicable in "heavy debugging" build.
* `a206debug` -- Controls FMPDRV.EXE function Ah subfunction 206h debug logging. Only applicable in "heavy debugging" build.
* `enabled` -- Enables/disables the ReelMagic emulator. By default this is `true`
* `alwaysresident` -- This forces `FMPDRV.EXE` to always be loaded. By default this is `false`
* `vgadup5hack` -- Duplicate every 5th VGA line to help give output a 4:3 ratio. By default this is `false`
* `initialmagickey` -- Provides and alternate value for the initial global "magic key" value in hex. Defaults to 40044041.
* `magicfhack` -- Use for MPEG video debugging purposes only. See `reelmagic_player.cpp` for what exactly this does to the MPEG decoder.
* `a204debug` -- Controls FMPDRV.EXE function Ah subfunction 204h debug logging. Only applicable in "heavy debugging" build.
* `a206debug` -- Controls FMPDRV.EXE function Ah subfunction 206h debug logging. Only applicable in "heavy debugging" build.


For example:
Expand Down
8 changes: 5 additions & 3 deletions dosbox-0.74-3/src/dosbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -661,12 +661,14 @@ void DOSBOX_Init(void) {
Pbool->Set_help("Force the FMPDRV.EXE to always be resident and not unloadable.");
Pbool = secprop->Add_bool("vgadup5hack",Property::Changeable::OnlyAtStart,false);
Pbool->Set_help("Enable the VGA DUP5 Hack. Duplicate's every VGA 5th line.");
Pint = secprop->Add_int("audiolevel", Property::Changeable::OnlyAtStart,150);
Pint = secprop->Add_int("audiolevel", Property::Changeable::OnlyAtStart,150);
Pint->Set_help("Sets the MPEG audio sample level in percents. Defaults to 150%");
Pint = secprop->Add_int("audiofifosize", Property::Changeable::OnlyAtStart,30);
Pint = secprop->Add_int("audiofifosize", Property::Changeable::OnlyAtStart,30);
Pint->Set_help("Sets the MPEG audio frame FIFO size. Defaults to 30 MPEG audio frames.");
Pint = secprop->Add_int("audiofifodispose", Property::Changeable::OnlyAtStart,2);
Pint = secprop->Add_int("audiofifodispose", Property::Changeable::OnlyAtStart,2);
Pint->Set_help("Sets the count of MPEG audio frames to dispose of when the MPEG is going faster than audio-side of things and the FIFO hits max. Defaults to 2.");
Pstring = secprop->Add_string("initialmagickey",Property::Changeable::OnlyAtStart,"40044041");
Pstring->Set_help("Provides and alternate value for the initial global \"magic key\" value in hex. Defaults to 40044041.");
Pint = secprop->Add_int("magicfhack",Property::Changeable::OnlyAtStart,0);
Pint->Set_help("MPEG debugging only! Consult the reelmagic_player.cpp source code and NOTES_MPEG.md");
Pbool = secprop->Add_bool("a204debug",Property::Changeable::OnlyAtStart,true);
Expand Down
35 changes: 23 additions & 12 deletions dosbox-0.74-3/src/hardware/reelmagic_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@
#include "./reelmagic_pl_mpeg.h"

//global config
static int _magicalFcodeOverride = 0; //0 = no override
static ReelMagic_PlayerConfiguration _globalDefaultPlayerConfiguration;
static double _audioLevel = 1.5;
static Bitu _audioFifoSize = 30;
static Bitu _audioFifoDispose = 2;
static Bitu _initialMagicKey = 0x40044041;
static int _magicalFcodeOverride = 0; //0 = no override



Expand Down Expand Up @@ -259,13 +260,13 @@ namespace { class ReelMagic_MediaPlayerImplementation : public ReelMagic_MediaPl
//the idea here is that MPEG-1 assets with a picture_rate code >= 0x9 in the MPEG sequence
//header have screwed up f_code values. i'm not sure why but this may be some form of copy
//and/or clone protection for ReelMagic. pictures with a temporal sequence number of either
//3 or 8 seem to contain a truthful f_code for Return to Zork and Lord of the Rings assets
//4 seems to contain the truthful f_code for The Horde. The Horde also has an empty user
//data chunk in the picture header too which is used to identify this.
//3 or 8 seem to contain a truthful f_code when a "key" of 0x40044041 (ReelMagic default)
//is given to us and a temporal sequence number of 4 seems to contain the truthful f_code
//when a "key" of 0xC39D7088 is given to us
//
//for now, this hack scrubs the MPEG file in search of the first P or B pictures with a
//temporal sequence number of 3 or 8 (or 4 for The Horde / user data) and returns the
//f_code value. then the player applies the f_code as a global static forward and
//temporal sequence number matching a truthful value based on the player's "magic key"
//the player then applies the found f_code value as a global static forward and
//backward value for this entire asset.
//
//ultimately, this should probably be done on a per-picture basis using some sort of
Expand All @@ -289,13 +290,18 @@ namespace { class ReelMagic_MediaPlayerImplementation : public ReelMagic_MediaPl
plm_buffer_skip(_plm->video_decoder->buffer, 16); // skip vbv_delay
plm_buffer_skip(_plm->video_decoder->buffer, 1); //skip full_px
result = plm_buffer_read(_plm->video_decoder->buffer, 3);
if (plm_buffer_next_start_code(_plm->video_decoder->buffer) == PLM_START_USER_DATA) {
// The Horde videos tsn=4 is truthful
switch (_config.MagicDecodeKey) {
case 0xC39D7088: //The Horde uses this "key"
if (temporal_seqnum != 4) result = 0;
}
else {
// Return to Zork and Lord of the Rings videos tsn=3 and tns=8 is truthful
break;

default:
LOG(LOG_REELMAGIC, LOG_WARN)("Unknown magic key 0x%08X. Defaulting to 0x40044041", (unsigned)_config.MagicDecodeKey);
//fall-through
case 0x40044041: //most ReelMagic games seem to use this "key"
//tsn=3 and tsn=8 seem to contain truthful
if ((temporal_seqnum != 3) && (temporal_seqnum != 8)) result = 0;
break;
}
}
} while (result == 0);
Expand Down Expand Up @@ -700,6 +706,11 @@ void ReelMagic_InitPlayer(Section* sec) {
_audioFifoSize = section->Get_int("audiofifosize");
_audioFifoDispose = section->Get_int("audiofifodispose");

//read in the initial global magic key from configuration
unsigned long scanval;
if (sscanf(section->Get_string("initialmagickey"), "%lX", &scanval) != 1) scanval = 0x40044041;
_initialMagicKey = scanval;

//XXX Remove this as it is ONLY for debugging MPEG assets!!!
_magicalFcodeOverride = section->Get_int("magicfhack");
if ((_magicalFcodeOverride < 0) || (_magicalFcodeOverride > 7))
Expand All @@ -716,7 +727,7 @@ void ReelMagic_ResetPlayers() {
cfg.VideoOutputVisible = true;
cfg.UnderVga = false;
cfg.VgaAlphaIndex = 0;
cfg.MagicDecodeKey = 0x40044041;
cfg.MagicDecodeKey = _initialMagicKey;
cfg.DisplayPosition.X = 0;
cfg.DisplayPosition.Y = 0;
cfg.DisplaySize.Width = 0;
Expand Down
2 changes: 2 additions & 0 deletions example.dosbox.conf
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ alwaysresident=true
#audiolevel=150
#audiofifosize=30
#audiofifodispose=2
#initialmagickey=40044041
#initialmagickey=C39D7088
#a204debug=false
#a206debug=false

Expand Down

0 comments on commit 0cb2f83

Please sign in to comment.