* [FFmpeg-devel] [PATCH v2 0/3] avcodec/sanm: Fixes for "StarWars - Making Magic"
@ 2025-05-06 15:40 Manuel Lauss
2025-05-06 15:40 ` [FFmpeg-devel] [PATCH v1 1/3] avcodec/sanm: ignore codec48 compression type 6 Manuel Lauss
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Manuel Lauss @ 2025-05-06 15:40 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Manuel Lauss
This patchset extends the SANM codec handler to support video of
the 1996 CD-ROM Title "StarWars - Making Magic".
These videos all consist of a 640x480 codec3 background, with 320x240
codec48 animations put on top at random left/top offsets.
v2: reworded descriptions, fixes in #3.
#1: some "Making Magic" files advertise codec48 compression type 6.
The actual data stops after the codec headers, and the dos exe as well as
the codec48 decoder in the MotS game exe don't know of it and simply
ignore it.
#2: change the FOBJ frame size determination to recognize common sizes.
With the scheme employed by Making Magic, the codec48 dimensions can no
longer be blindly trusted.
#3: support video of Making Magic. This patch also brings the fobj
handling more in line with what the game engines actually do.
Tested with RA1, RA2 (c37), Outlaws (c47), MotS (c48)
See https://ibb.co/73Pt803 for post/pre fix screenshots.
Manuel Lauss (3):
avcodec/sanm: ignore codec48 compression type 6
avcodec/sanm: add a whitelist for known FOBJ sizes
avcodec/sanm: support "StarWars - Making Magic" video
libavcodec/sanm.c | 100 ++++++++++++++++++++++++++++++++--------------
1 file changed, 70 insertions(+), 30 deletions(-)
--
2.49.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH v1 1/3] avcodec/sanm: ignore codec48 compression type 6
2025-05-06 15:40 [FFmpeg-devel] [PATCH v2 0/3] avcodec/sanm: Fixes for "StarWars - Making Magic" Manuel Lauss
@ 2025-05-06 15:40 ` Manuel Lauss
2025-05-06 15:40 ` [FFmpeg-devel] [PATCH v2 2/3] avcodec/sanm: recognize common FOBJ sizes Manuel Lauss
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Manuel Lauss @ 2025-05-06 15:40 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Manuel Lauss
Some videos of "StarWars - Making Magic" have this subcompression
type: data just consists of the 16 byte codec48 header; the DOS player
and the c48 decoder in the Myteries of the Sith game engine ignore it.
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
v2: reworded description
libavcodec/sanm.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 6b1da2e30c..e436b5ab8e 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -1586,7 +1586,8 @@ static int old_codec48(SANMVideoContext *ctx, int width, int height)
return AVERROR_INVALIDDATA;
codec47_comp1(ctx, dst, width, height, width);
break;
-
+ case 6: /* in some videos, but does nothing */
+ break;
default:
avpriv_report_missing_feature(ctx->avctx,
"Subcodec 48 compression %d", compr);
--
2.49.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH v2 2/3] avcodec/sanm: recognize common FOBJ sizes
2025-05-06 15:40 [FFmpeg-devel] [PATCH v2 0/3] avcodec/sanm: Fixes for "StarWars - Making Magic" Manuel Lauss
2025-05-06 15:40 ` [FFmpeg-devel] [PATCH v1 1/3] avcodec/sanm: ignore codec48 compression type 6 Manuel Lauss
@ 2025-05-06 15:40 ` Manuel Lauss
2025-05-06 15:40 ` [FFmpeg-devel] [PATCH v2 3/3] avcodec/sanm: support "StarWars - Making Magic" video Manuel Lauss
2025-05-07 7:00 ` [FFmpeg-devel] [PATCH v2 0/3] avcodec/sanm: Fixes for "StarWars - Making Magic" Manuel Lauss
3 siblings, 0 replies; 5+ messages in thread
From: Manuel Lauss @ 2025-05-06 15:40 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Manuel Lauss
Change the size detection a bit to recognize common video sizes,
as the FOBJ codecs>=37 cannot always be trusted, since they can
be embedded in a larger frame.
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
v2: reworded description.
libavcodec/sanm.c | 34 +++++++++++++++++++++++++++-------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index e436b5ab8e..63f5c2cc7f 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -1603,6 +1603,7 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
uint16_t w, h, parm2;
uint8_t codec, param;
int16_t left, top;
+ int fsc, sote;
codec = bytestream2_get_byteu(gb);
param = bytestream2_get_byteu(gb);
@@ -1620,6 +1621,14 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
return 0;
}
+ /* codecs with their own buffers */
+ fsc = (codec == 37 || codec == 47 || codec == 48);
+
+ /* special case for "Shadows of the Empire" videos */
+ sote = ((w == 640) && (h == 272) && (codec == 47));
+ if (sote)
+ left = top = 0;
+
if (!ctx->have_dimensions) {
int xres, yres;
if (ctx->subversion < 2) {
@@ -1633,12 +1642,24 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
yres = h;
ctx->have_dimensions = 1;
} else {
- /* Rebel Assault 2: 424x260 internal size */
- if (((left + w) == 424) && ((top + h) == 260))
+ /* detect common sizes */
+ xres = w + left;
+ yres = h + top;
+ if (sote) {
+ /* SotE: has top=60 at all times to center video
+ * inside the 640x480 game window
+ */
+ xres = w;
+ yres = h;
ctx->have_dimensions = 1;
+ } else if (((xres == 424) && (yres == 260)) || /* RA1 */
+ ((xres == 320) && (yres == 200)) || /* ft/dig/... */
+ ((xres == 640) && (yres == 480))) { /* ol/comi/mots... */
+ ctx->have_dimensions = 1;
+ }
- xres = FFMAX(left + w, ctx->width);
- yres = FFMAX(top + h, ctx->height);
+ xres = FFMAX(xres, ctx->width);
+ yres = FFMAX(yres, ctx->height);
}
if (ctx->width < xres || ctx->height < yres) {
@@ -1652,8 +1673,7 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
}
}
} else {
- if (((left + w > ctx->width) || (top + h > ctx->height))
- && (codec >= 37)) {
+ if (((left + w > ctx->width) || (top + h > ctx->height)) && fsc) {
/* correct unexpected overly large frames: this happens
* for instance with The Dig's sq1.san video: it has a few
* (all black) 640x480 frames halfway in, while the rest is
@@ -1671,7 +1691,7 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
*/
if (ctx->first_fob) {
ctx->first_fob = 0;
- if (codec < 37)
+ if (!fsc)
memset(ctx->frm0, 0, ctx->frm0_size);
}
--
2.49.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH v2 3/3] avcodec/sanm: support "StarWars - Making Magic" video
2025-05-06 15:40 [FFmpeg-devel] [PATCH v2 0/3] avcodec/sanm: Fixes for "StarWars - Making Magic" Manuel Lauss
2025-05-06 15:40 ` [FFmpeg-devel] [PATCH v1 1/3] avcodec/sanm: ignore codec48 compression type 6 Manuel Lauss
2025-05-06 15:40 ` [FFmpeg-devel] [PATCH v2 2/3] avcodec/sanm: recognize common FOBJ sizes Manuel Lauss
@ 2025-05-06 15:40 ` Manuel Lauss
2025-05-07 7:00 ` [FFmpeg-devel] [PATCH v2 0/3] avcodec/sanm: Fixes for "StarWars - Making Magic" Manuel Lauss
3 siblings, 0 replies; 5+ messages in thread
From: Manuel Lauss @ 2025-05-06 15:40 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Manuel Lauss
Videos of "StarWars - Making Magic" consist of 640x480 codec3 frames
which establish a background, and a 320x240 codec48 video put on top
at random left/top offsets.
To support this, a new default buffer "fbuf", which holds the final
image to be presented, is added, since codec37/47/48 need their 2/3 buffers
to be private to themselves. The decoded result is then copied to the fbuf,
honoring the left/top offsets if required.
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
v2: reworded description, left/top need to be non-negative to consider
the image to be copied to front buffer fbuf.
libavcodec/sanm.c | 65 ++++++++++++++++++++++++++++++-----------------
1 file changed, 42 insertions(+), 23 deletions(-)
diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 63f5c2cc7f..188f7db3c0 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -274,9 +274,9 @@ typedef struct SANMVideoContext {
int prev_seq;
AVFrame *frame;
- uint16_t *frm0, *frm1, *frm2;
+ uint16_t *fbuf, *frm0, *frm1, *frm2;
uint8_t *stored_frame;
- uint32_t frm0_size, frm1_size, frm2_size;
+ uint32_t fbuf_size, frm0_size, frm1_size, frm2_size;
uint32_t stored_frame_size;
uint8_t *rle_buf;
@@ -453,6 +453,7 @@ static void init_sizes(SANMVideoContext *ctx, int width, int height)
static void destroy_buffers(SANMVideoContext *ctx)
{
+ av_freep(&ctx->fbuf);
av_freep(&ctx->frm0);
av_freep(&ctx->frm1);
av_freep(&ctx->frm2);
@@ -466,6 +467,7 @@ static void destroy_buffers(SANMVideoContext *ctx)
static av_cold int init_buffers(SANMVideoContext *ctx)
{
+ av_fast_padded_mallocz(&ctx->fbuf, &ctx->fbuf_size, ctx->buf_size);
av_fast_padded_mallocz(&ctx->frm0, &ctx->frm0_size, ctx->buf_size);
av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_size, ctx->buf_size);
av_fast_padded_mallocz(&ctx->frm2, &ctx->frm2_size, ctx->buf_size);
@@ -674,7 +676,7 @@ static int old_codec4(SANMVideoContext *ctx, GetByteContext *gb, int top, int le
{
const uint16_t p = ctx->pitch;
const uint32_t maxpxo = ctx->height * p;
- uint8_t mask, bits, idx, *gs, *dst = (uint8_t *)ctx->frm0;
+ uint8_t mask, bits, idx, *gs, *dst = (uint8_t *)ctx->fbuf;
int i, j, k, l, bit, ret;
int32_t pxoff, pxo2;
@@ -805,7 +807,7 @@ static int old_codec23(SANMVideoContext *ctx, GetByteContext *gb, int top, int l
if (bytestream2_get_bytes_left(gb) < 1)
return 0; /* some c23 frames just set up the LUT */
- dst = (uint8_t *)ctx->frm0;
+ dst = (uint8_t *)ctx->fbuf;
for (i = 0; i < height; i++) {
if (bytestream2_get_bytes_left(gb) < 2)
return 0;
@@ -840,10 +842,10 @@ static int old_codec21(SANMVideoContext *ctx, GetByteContext *gb, int top, int l
int width, int height)
{
const uint32_t maxpxo = ctx->height * ctx->pitch;
- uint8_t *dst = (uint8_t *)ctx->frm0, c;
+ uint8_t *dst = (uint8_t *)ctx->fbuf, c;
int i, j, k, pc, sk, pxoff;
- dst = (uint8_t *)ctx->frm0;
+ dst = (uint8_t *)ctx->fbuf;
for (i = 0; i < height; i++) {
if (bytestream2_get_bytes_left(gb) < 2)
return 0;
@@ -884,7 +886,7 @@ static int old_codec1(SANMVideoContext *ctx, GetByteContext *gb, int top,
{
int i, j, len, flag, code, val, end, pxoff;
const int maxpxo = ctx->height * ctx->pitch;
- uint8_t *dst = (uint8_t *)ctx->frm0;
+ uint8_t *dst = (uint8_t *)ctx->fbuf;
for (i = 0; i < height; i++) {
if (bytestream2_get_bytes_left(gb) < 2)
@@ -932,7 +934,7 @@ static int old_codec1(SANMVideoContext *ctx, GetByteContext *gb, int top,
static int old_codec2(SANMVideoContext *ctx, GetByteContext *gb, int top,
int left, int width, int height)
{
- uint8_t *dst = (uint8_t *)ctx->frm0, col;
+ uint8_t *dst = (uint8_t *)ctx->fbuf, col;
int16_t xpos = left, ypos = top;
while (bytestream2_get_bytes_left(gb) > 3) {
@@ -949,7 +951,7 @@ static int old_codec2(SANMVideoContext *ctx, GetByteContext *gb, int top,
static int old_codec20(SANMVideoContext *ctx, int w, int h)
{
- uint8_t *dst = (uint8_t *)ctx->frm0;
+ uint8_t *dst = (uint8_t *)ctx->fbuf;
if (bytestream2_get_bytes_left(&ctx->gb) < w * h)
return AVERROR_INVALIDDATA;
@@ -1008,10 +1010,10 @@ static int old_codec37(SANMVideoContext *ctx, int width, int height)
ctx->rotate_code = 0;
if (((seq & 1) || !(flags & 1)) && (compr && compr != 2)) {
- FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
+ FFSWAP(uint16_t*, ctx->frm0, ctx->frm2);
}
- dst = ((uint8_t*)ctx->frm1);
+ dst = ((uint8_t*)ctx->frm0);
prev = ((uint8_t*)ctx->frm2);
if (mvoff > 2) {
@@ -1145,7 +1147,6 @@ static int old_codec37(SANMVideoContext *ctx, int width, int height)
return AVERROR_PATCHWELCOME;
}
- memcpy(ctx->frm0, ctx->frm1, ctx->buf_size);
return 0;
}
@@ -1603,7 +1604,7 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
uint16_t w, h, parm2;
uint8_t codec, param;
int16_t left, top;
- int fsc, sote;
+ int fsc, sote, ret;
codec = bytestream2_get_byteu(gb);
param = bytestream2_get_byteu(gb);
@@ -1686,13 +1687,11 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
}
}
- /* on first FOBJ, when the codec is not one of the
- * full-buffer codecs (37/47/48), frm0 needs to be cleared.
- */
+ /* clear the main buffer on the first fob */
if (ctx->first_fob) {
ctx->first_fob = 0;
if (!fsc)
- memset(ctx->frm0, 0, ctx->frm0_size);
+ memset(ctx->fbuf, 0, ctx->frm0_size);
}
switch (codec) {
@@ -1713,18 +1712,38 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
case 23:
return old_codec23(ctx, gb, top, left, w, h, param, parm2);
case 37:
- return old_codec37(ctx, w, h);
+ ret = old_codec37(ctx, w, h); break;
case 45:
return 0;
case 47:
- return old_codec47(ctx, w, h);
+ ret = old_codec47(ctx, w, h); break;
case 48:
- return old_codec48(ctx, w, h);
+ ret = old_codec48(ctx, w, h); break;
default:
avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
ctx->frame->flags |= AV_FRAME_FLAG_CORRUPT;
return 0;
}
+ if (ret)
+ return ret;
+
+ /* copy the codec37/47/48 result to main buffer */
+ if ((w == ctx->width) && (h == ctx->height)) {
+ memcpy(ctx->fbuf, ctx->frm0, ctx->fbuf_size);
+ } else {
+ uint8_t *dst = (uint8_t *)ctx->fbuf + left + top * ctx->pitch;
+ const uint8_t *src = (uint8_t *)ctx->frm0;
+ const int cw = FFMIN(w, ctx->width - left);
+ const int ch = FFMIN(h, ctx->height - top);
+ if ((cw > 0) && (ch > 0) && (left >= 0) && (top >= 0)) {
+ for (int i = 0; i < ch; i++) {
+ memcpy(dst, src, cw);
+ dst += ctx->pitch;
+ src += w;
+ }
+ }
+ }
+ return 0;
}
static int process_ftch(SANMVideoContext *ctx, int size)
@@ -2196,7 +2215,7 @@ static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr)
{
uint8_t *dst;
- const uint8_t *src = (uint8_t*) ctx->frm0;
+ const uint8_t *src = hdr ? (uint8_t *)ctx->frm0 : (uint8_t *)ctx->fbuf;
int ret, height = ctx->height;
ptrdiff_t dstpitch, srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1);
@@ -2279,7 +2298,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
ret = AVERROR(ENOMEM);
}
} else {
- memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
+ memcpy(ctx->stored_frame, ctx->fbuf, ctx->buf_size);
}
}
break;
@@ -2295,7 +2314,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
if (ret = process_ftch(ctx, size))
return ret;
} else {
- memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
+ memcpy(ctx->fbuf, ctx->stored_frame, ctx->buf_size);
}
have_img = 1;
break;
--
2.49.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [FFmpeg-devel] [PATCH v2 0/3] avcodec/sanm: Fixes for "StarWars - Making Magic"
2025-05-06 15:40 [FFmpeg-devel] [PATCH v2 0/3] avcodec/sanm: Fixes for "StarWars - Making Magic" Manuel Lauss
` (2 preceding siblings ...)
2025-05-06 15:40 ` [FFmpeg-devel] [PATCH v2 3/3] avcodec/sanm: support "StarWars - Making Magic" video Manuel Lauss
@ 2025-05-07 7:00 ` Manuel Lauss
3 siblings, 0 replies; 5+ messages in thread
From: Manuel Lauss @ 2025-05-07 7:00 UTC (permalink / raw)
To: ffmpeg-devel
Hi,
If there are no objections, I will commit this with whitespace fixes
in 2-3 days. I see no regressions with existing sanm video support.
Manuel
On Tue, May 6, 2025 at 5:41 PM Manuel Lauss <manuel.lauss@gmail.com> wrote:
>
> This patchset extends the SANM codec handler to support video of
> the 1996 CD-ROM Title "StarWars - Making Magic".
> These videos all consist of a 640x480 codec3 background, with 320x240
> codec48 animations put on top at random left/top offsets.
>
> v2: reworded descriptions, fixes in #3.
>
> #1: some "Making Magic" files advertise codec48 compression type 6.
> The actual data stops after the codec headers, and the dos exe as well as
> the codec48 decoder in the MotS game exe don't know of it and simply
> ignore it.
>
> #2: change the FOBJ frame size determination to recognize common sizes.
> With the scheme employed by Making Magic, the codec48 dimensions can no
> longer be blindly trusted.
>
> #3: support video of Making Magic. This patch also brings the fobj
> handling more in line with what the game engines actually do.
>
> Tested with RA1, RA2 (c37), Outlaws (c47), MotS (c48)
>
> See https://ibb.co/73Pt803 for post/pre fix screenshots.
>
> Manuel Lauss (3):
> avcodec/sanm: ignore codec48 compression type 6
> avcodec/sanm: add a whitelist for known FOBJ sizes
> avcodec/sanm: support "StarWars - Making Magic" video
>
> libavcodec/sanm.c | 100 ++++++++++++++++++++++++++++++++--------------
> 1 file changed, 70 insertions(+), 30 deletions(-)
>
> --
> 2.49.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-05-07 7:01 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-06 15:40 [FFmpeg-devel] [PATCH v2 0/3] avcodec/sanm: Fixes for "StarWars - Making Magic" Manuel Lauss
2025-05-06 15:40 ` [FFmpeg-devel] [PATCH v1 1/3] avcodec/sanm: ignore codec48 compression type 6 Manuel Lauss
2025-05-06 15:40 ` [FFmpeg-devel] [PATCH v2 2/3] avcodec/sanm: recognize common FOBJ sizes Manuel Lauss
2025-05-06 15:40 ` [FFmpeg-devel] [PATCH v2 3/3] avcodec/sanm: support "StarWars - Making Magic" video Manuel Lauss
2025-05-07 7:00 ` [FFmpeg-devel] [PATCH v2 0/3] avcodec/sanm: Fixes for "StarWars - Making Magic" Manuel Lauss
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git