You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-04 22:03:09 +02:00
avcodec/sanm: support "StarWars - Making Magic" video
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>
This commit is contained in:
@ -274,9 +274,9 @@ typedef struct SANMVideoContext {
|
|||||||
int prev_seq;
|
int prev_seq;
|
||||||
|
|
||||||
AVFrame *frame;
|
AVFrame *frame;
|
||||||
uint16_t *frm0, *frm1, *frm2;
|
uint16_t *fbuf, *frm0, *frm1, *frm2;
|
||||||
uint8_t *stored_frame;
|
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;
|
uint32_t stored_frame_size;
|
||||||
|
|
||||||
uint8_t *rle_buf;
|
uint8_t *rle_buf;
|
||||||
@ -453,6 +453,7 @@ static void init_sizes(SANMVideoContext *ctx, int width, int height)
|
|||||||
|
|
||||||
static void destroy_buffers(SANMVideoContext *ctx)
|
static void destroy_buffers(SANMVideoContext *ctx)
|
||||||
{
|
{
|
||||||
|
av_freep(&ctx->fbuf);
|
||||||
av_freep(&ctx->frm0);
|
av_freep(&ctx->frm0);
|
||||||
av_freep(&ctx->frm1);
|
av_freep(&ctx->frm1);
|
||||||
av_freep(&ctx->frm2);
|
av_freep(&ctx->frm2);
|
||||||
@ -466,6 +467,7 @@ static void destroy_buffers(SANMVideoContext *ctx)
|
|||||||
|
|
||||||
static av_cold int init_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->frm0, &ctx->frm0_size, ctx->buf_size);
|
||||||
av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_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);
|
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 uint16_t p = ctx->pitch;
|
||||||
const uint32_t maxpxo = ctx->height * p;
|
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;
|
int i, j, k, l, bit, ret;
|
||||||
int32_t pxoff, pxo2;
|
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)
|
if (bytestream2_get_bytes_left(gb) < 1)
|
||||||
return 0; /* some c23 frames just set up the LUT */
|
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++) {
|
for (i = 0; i < height; i++) {
|
||||||
if (bytestream2_get_bytes_left(gb) < 2)
|
if (bytestream2_get_bytes_left(gb) < 2)
|
||||||
return 0;
|
return 0;
|
||||||
@ -840,10 +842,10 @@ static int old_codec21(SANMVideoContext *ctx, GetByteContext *gb, int top, int l
|
|||||||
int width, int height)
|
int width, int height)
|
||||||
{
|
{
|
||||||
const uint32_t maxpxo = ctx->height * ctx->pitch;
|
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;
|
int i, j, k, pc, sk, pxoff;
|
||||||
|
|
||||||
dst = (uint8_t *)ctx->frm0;
|
dst = (uint8_t *)ctx->fbuf;
|
||||||
for (i = 0; i < height; i++) {
|
for (i = 0; i < height; i++) {
|
||||||
if (bytestream2_get_bytes_left(gb) < 2)
|
if (bytestream2_get_bytes_left(gb) < 2)
|
||||||
return 0;
|
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;
|
int i, j, len, flag, code, val, end, pxoff;
|
||||||
const int maxpxo = ctx->height * ctx->pitch;
|
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++) {
|
for (i = 0; i < height; i++) {
|
||||||
if (bytestream2_get_bytes_left(gb) < 2)
|
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,
|
static int old_codec2(SANMVideoContext *ctx, GetByteContext *gb, int top,
|
||||||
int left, int width, int height)
|
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;
|
int16_t xpos = left, ypos = top;
|
||||||
|
|
||||||
while (bytestream2_get_bytes_left(gb) > 3) {
|
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)
|
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)
|
if (bytestream2_get_bytes_left(&ctx->gb) < w * h)
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
@ -1008,10 +1010,10 @@ static int old_codec37(SANMVideoContext *ctx, int width, int height)
|
|||||||
ctx->rotate_code = 0;
|
ctx->rotate_code = 0;
|
||||||
|
|
||||||
if (((seq & 1) || !(flags & 1)) && (compr && compr != 2)) {
|
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);
|
prev = ((uint8_t*)ctx->frm2);
|
||||||
|
|
||||||
if (mvoff > 2) {
|
if (mvoff > 2) {
|
||||||
@ -1145,7 +1147,6 @@ static int old_codec37(SANMVideoContext *ctx, int width, int height)
|
|||||||
return AVERROR_PATCHWELCOME;
|
return AVERROR_PATCHWELCOME;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(ctx->frm0, ctx->frm1, ctx->buf_size);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1603,7 +1604,7 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
|
|||||||
uint16_t w, h, parm2;
|
uint16_t w, h, parm2;
|
||||||
uint8_t codec, param;
|
uint8_t codec, param;
|
||||||
int16_t left, top;
|
int16_t left, top;
|
||||||
int fsc, sote;
|
int fsc, sote, ret;
|
||||||
|
|
||||||
codec = bytestream2_get_byteu(gb);
|
codec = bytestream2_get_byteu(gb);
|
||||||
param = 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
|
/* clear the main buffer on the first fob */
|
||||||
* full-buffer codecs (37/47/48), frm0 needs to be cleared.
|
|
||||||
*/
|
|
||||||
if (ctx->first_fob) {
|
if (ctx->first_fob) {
|
||||||
ctx->first_fob = 0;
|
ctx->first_fob = 0;
|
||||||
if (!fsc)
|
if (!fsc)
|
||||||
memset(ctx->frm0, 0, ctx->frm0_size);
|
memset(ctx->fbuf, 0, ctx->frm0_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (codec) {
|
switch (codec) {
|
||||||
@ -1713,18 +1712,38 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
|
|||||||
case 23:
|
case 23:
|
||||||
return old_codec23(ctx, gb, top, left, w, h, param, parm2);
|
return old_codec23(ctx, gb, top, left, w, h, param, parm2);
|
||||||
case 37:
|
case 37:
|
||||||
return old_codec37(ctx, w, h);
|
ret = old_codec37(ctx, w, h); break;
|
||||||
case 45:
|
case 45:
|
||||||
return 0;
|
return 0;
|
||||||
case 47:
|
case 47:
|
||||||
return old_codec47(ctx, w, h);
|
ret = old_codec47(ctx, w, h); break;
|
||||||
case 48:
|
case 48:
|
||||||
return old_codec48(ctx, w, h);
|
ret = old_codec48(ctx, w, h); break;
|
||||||
default:
|
default:
|
||||||
avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
|
avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
|
||||||
ctx->frame->flags |= AV_FRAME_FLAG_CORRUPT;
|
ctx->frame->flags |= AV_FRAME_FLAG_CORRUPT;
|
||||||
return 0;
|
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)
|
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)
|
static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr)
|
||||||
{
|
{
|
||||||
uint8_t *dst;
|
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;
|
int ret, height = ctx->height;
|
||||||
ptrdiff_t dstpitch, srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1);
|
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);
|
ret = AVERROR(ENOMEM);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
|
memcpy(ctx->stored_frame, ctx->fbuf, ctx->buf_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2295,7 +2314,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
|
|||||||
if (ret = process_ftch(ctx, size))
|
if (ret = process_ftch(ctx, size))
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
|
memcpy(ctx->fbuf, ctx->stored_frame, ctx->buf_size);
|
||||||
}
|
}
|
||||||
have_img = 1;
|
have_img = 1;
|
||||||
break;
|
break;
|
||||||
|
Reference in New Issue
Block a user