Skip to content

Commit 21aa37a

Browse files
committed
Implement support for interplay MVE 0x06 and 0x10
1 parent 18f0952 commit 21aa37a

File tree

2 files changed

+340
-39
lines changed

2 files changed

+340
-39
lines changed

libavcodec/interplayvideo.c

Lines changed: 263 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,17 @@ typedef struct IpvideoContext {
5555
HpelDSPContext hdsp;
5656
AVFrame *second_last_frame;
5757
AVFrame *last_frame;
58+
59+
/* For format 0x10 */
60+
AVFrame *cur_decode_frame;
61+
AVFrame *prev_decode_frame;
62+
63+
uint8_t frame_format;
64+
const unsigned char *skip_map;
65+
int skip_map_size;
5866
const unsigned char *decoding_map;
5967
int decoding_map_size;
68+
int video_data_size;
6069

6170
int is_16bpp;
6271
GetByteContext stream_ptr, mv_ptr;
@@ -903,7 +912,188 @@ static int (* const ipvideo_decode_block16[])(IpvideoContext *s, AVFrame *frame)
903912
ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1,
904913
};
905914

906-
static void ipvideo_decode_opcodes(IpvideoContext *s, AVFrame *frame)
915+
916+
static void ipvideo_decode_format_06_opcodes(IpvideoContext *s, AVFrame *frame)
917+
{
918+
int x, y, off_x, off_y;
919+
const unsigned char* decode_map_p;
920+
short opcode;
921+
922+
if (!s->is_16bpp) {
923+
/* this is PAL8, so make the palette available */
924+
memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
925+
926+
s->stride = frame->linesize[0];
927+
}
928+
929+
s->line_inc = s->stride - 8;
930+
s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0]
931+
+ (s->avctx->width - 8) * (1 + s->is_16bpp);
932+
933+
decode_map_p = s->decoding_map;
934+
for (y = 0; y < s->avctx->height; y += 8) {
935+
for (x = 0; x < s->avctx->width; x += 8) {
936+
opcode = AV_RL16(decode_map_p);
937+
938+
ff_tlog(s->avctx,
939+
" block @ (%3d, %3d): opcode 0x%X, data ptr offset %d\n",
940+
x, y, opcode, bytestream2_tell(&s->stream_ptr));
941+
942+
s->pixel_ptr = frame->data[0] + x + y*frame->linesize[0];
943+
if(! opcode) {
944+
int k;
945+
for (k = 0; k < 8; k++) {
946+
bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8);
947+
s->pixel_ptr += s->stride;
948+
}
949+
} else {
950+
copy_from(s, s->second_last_frame, frame, 0, 0);
951+
}
952+
decode_map_p += 2;
953+
}
954+
}
955+
956+
decode_map_p = s->decoding_map;
957+
for (y = 0; y < s->avctx->height; y += 8) {
958+
for (x = 0; x < s->avctx->width; x += 8) {
959+
opcode = AV_RL16(decode_map_p);
960+
961+
ff_tlog(s->avctx,
962+
" block @ (%3d, %3d): opcode 0x%X, data ptr offset %d\n",
963+
x, y, opcode, bytestream2_tell(&s->stream_ptr));
964+
965+
s->pixel_ptr = frame->data[0] + x + y*frame->linesize[0];
966+
if(opcode < 0) {
967+
off_x = ((unsigned short)opcode - 0xC000) % frame->linesize[0];
968+
off_y = ((unsigned short)opcode - 0xC000) / frame->linesize[0];
969+
copy_from(s, s->last_frame, frame, off_x, off_y);
970+
}
971+
if(opcode > 0) {
972+
off_x = ((unsigned short)opcode - 0x4000) % frame->linesize[0];
973+
off_y = ((unsigned short)opcode - 0x4000) / frame->linesize[0];
974+
copy_from(s, frame, frame, off_x, off_y);
975+
}
976+
decode_map_p += 2;
977+
}
978+
}
979+
980+
if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) {
981+
av_log(s->avctx, AV_LOG_DEBUG,
982+
"decode finished with %d bytes left over\n",
983+
bytestream2_get_bytes_left(&s->stream_ptr));
984+
}
985+
}
986+
987+
static void ipvideo_decode_format_10_opcodes(IpvideoContext *s, AVFrame *frame)
988+
{
989+
int x, y, off_x, off_y;
990+
const unsigned char* decode_map_p;
991+
const unsigned char* skip_map_p;
992+
short opcode, skip;
993+
int changed_block = 0;
994+
995+
if (!s->is_16bpp) {
996+
/* this is PAL8, so make the palette available */
997+
memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
998+
999+
s->stride = frame->linesize[0];
1000+
}
1001+
1002+
bytestream2_skip(&s->stream_ptr, 14); /* data starts 14 bytes in */
1003+
1004+
s->line_inc = s->stride - 8;
1005+
s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0]
1006+
+ (s->avctx->width - 8) * (1 + s->is_16bpp);
1007+
1008+
decode_map_p = s->decoding_map;
1009+
skip_map_p = s->skip_map;
1010+
skip = AV_RL16(skip_map_p);
1011+
for (y = 0; y < s->avctx->height; y += 8) {
1012+
for (x = 0; x < s->avctx->width; x += 8) {
1013+
s->pixel_ptr = s->cur_decode_frame->data[0] + x + y*cur_decode_frame->linesize[0];
1014+
1015+
while (skip <= 0) {
1016+
if (skip != -0x8000 && skip != 0) {
1017+
opcode = AV_RL16(decode_map_p);
1018+
if(! opcode) {
1019+
int k;
1020+
for (k = 0; k < 8; k++) {
1021+
bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8);
1022+
s->pixel_ptr += s->stride;
1023+
}
1024+
}
1025+
decode_map_p += 2;
1026+
break;
1027+
}
1028+
skip_map_p += 2;
1029+
skip = AV_RL16(skip_map_p);
1030+
}
1031+
skip *= 2;
1032+
}
1033+
}
1034+
1035+
decode_map_p = s->decoding_map;
1036+
skip_map_p = s->skip_map;
1037+
skip = AV_RL16(skip_map_p);
1038+
for (y = 0; y < s->avctx->height; y += 8) {
1039+
for (x = 0; x < s->avctx->width; x += 8) {
1040+
s->pixel_ptr = s->cur_decode_frame->data[0] + x + y*cur_decode_frame->linesize[0];
1041+
1042+
while (skip <= 0) {
1043+
if (skip != -0x8000 && skip != 0) {
1044+
opcode = AV_RL16(decode_map_p);
1045+
if(opcode < 0) {
1046+
off_x = ((unsigned short)opcode - 0xC000) % cur_decode_frame->linesize[0];
1047+
off_y = ((unsigned short)opcode - 0xC000) / cur_decode_frame->linesize[0];
1048+
copy_from(s, s->prev_decode_frame, s->cur_decode_frame, off_x, off_y);
1049+
}
1050+
if(opcode > 0) {
1051+
off_x = ((unsigned short)opcode - 0x4000) % cur_decode_frame->linesize[0];
1052+
off_y = ((unsigned short)opcode - 0x4000) / cur_decode_frame->linesize[0];
1053+
copy_from(s, s->cur_decode_frame, s->cur_decode_frame, off_x, off_y);
1054+
}
1055+
decode_map_p += 2;
1056+
break;
1057+
}
1058+
skip_map_p += 2;
1059+
skip = AV_RL16(skip_map_p);
1060+
}
1061+
skip *= 2;
1062+
}
1063+
}
1064+
1065+
skip_map_p = s->skip_map;
1066+
skip = AV_RL16(skip_map_p);
1067+
for (y = 0; y < s->avctx->height; y += 8) {
1068+
for (x = 0; x < s->avctx->width; x += 8) {
1069+
changed_block = 0;
1070+
s->pixel_ptr = frame->data[0] + x + y*frame->linesize[0];
1071+
while (skip <= 0) {
1072+
if (skip != -0x8000 && skip != 0) {
1073+
changed_block = 1;
1074+
break;
1075+
}
1076+
skip_map_p += 2;
1077+
skip = AV_RL16(skip_map_p);
1078+
}
1079+
if(changed_block)
1080+
copy_from(s, s->cur_decode_frame, frame, 0, 0);
1081+
else
1082+
copy_from(s, s->last_frame, frame, 0, 0);
1083+
skip *= 2;
1084+
}
1085+
}
1086+
1087+
FFSWAP(AVFrame*, s->prev_decode_frame, s->cur_decode_frame);
1088+
1089+
if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) {
1090+
av_log(s->avctx, AV_LOG_DEBUG,
1091+
"decode finished with %d bytes left over\n",
1092+
bytestream2_get_bytes_left(&s->stream_ptr));
1093+
}
1094+
}
1095+
1096+
static void ipvideo_decode_format_11_opcodes(IpvideoContext *s, AVFrame *frame)
9071097
{
9081098
int x, y;
9091099
unsigned char opcode;
@@ -972,12 +1162,26 @@ static av_cold int ipvideo_decode_init(AVCodecContext *avctx)
9721162

9731163
s->last_frame = av_frame_alloc();
9741164
s->second_last_frame = av_frame_alloc();
975-
if (!s->last_frame || !s->second_last_frame) {
1165+
s->cur_decode_frame = av_frame_alloc();
1166+
s->prev_decode_frame = av_frame_alloc();
1167+
if (!s->last_frame || !s->second_last_frame ||
1168+
!s->cur_decode_frame || !s->prev_decode_frame) {
9761169
av_frame_free(&s->last_frame);
9771170
av_frame_free(&s->second_last_frame);
1171+
av_frame_free(&s->cur_decode_frame);
1172+
av_frame_free(&s->prev_decode_frame);
9781173
return AVERROR(ENOMEM);
9791174
}
9801175

1176+
s->cur_decode_frame->width = avctx->width;
1177+
s->prev_decode_frame->width = avctx->width;
1178+
s->cur_decode_frame->height = avctx->height;
1179+
s->prev_decode_frame->height = avctx->height;
1180+
s->cur_decode_frame->format = avctx->pix_fmt;
1181+
s->prev_decode_frame->format = avctx->pix_fmt;
1182+
1183+
ff_get_buffer(avctx, s->cur_decode_frame, 0);
1184+
ff_get_buffer(avctx, s->prev_decode_frame, 0);
9811185
return 0;
9821186
}
9831187

@@ -999,18 +1203,53 @@ static int ipvideo_decode_frame(AVCodecContext *avctx,
9991203
if (buf_size < 2)
10001204
return AVERROR_INVALIDDATA;
10011205

1002-
/* decoding map contains 4 bits of information per 8x8 block */
1003-
s->decoding_map_size = AV_RL16(avpkt->data);
1004-
1005-
/* compressed buffer needs to be large enough to at least hold an entire
1006-
* decoding map */
1007-
if (buf_size < s->decoding_map_size + 2)
1008-
return buf_size;
1009-
1010-
1011-
s->decoding_map = buf + 2;
1012-
bytestream2_init(&s->stream_ptr, buf + 2 + s->decoding_map_size,
1013-
buf_size - s->decoding_map_size);
1206+
s->frame_format = AV_RB8(avpkt->data);
1207+
switch (s->frame_format) {
1208+
case 0x06:
1209+
/* Format 0x06 has decoding map appended to the top of pixel data */
1210+
/* decoding map contains 16 bits of information per 8x8 block */
1211+
s->decoding_map_size = ((s->avctx->width / 8) * (s->avctx->height / 8)) * 2;
1212+
s->decoding_map = buf + 3 + 14; /* 14 bits of op data */
1213+
1214+
s->video_data_size = AV_RL16(avpkt->data + 1) - s->decoding_map_size - 14;
1215+
bytestream2_init(&s->stream_ptr, buf + 3 + s->decoding_map_size + 14, s->video_data_size);
1216+
1217+
if (buf_size < s->decoding_map_size + 2)
1218+
return buf_size;
1219+
break;
1220+
1221+
case 0x10:
1222+
/* Format 0x10 has a decoding map, pixel data, and a skip map */
1223+
s->video_data_size = AV_RL16(avpkt->data + 1);
1224+
bytestream2_init(&s->stream_ptr, buf + 3, s->video_data_size);
1225+
1226+
/* decoding map contains 16 bits of information per 8x8 block */
1227+
s->decoding_map_size = AV_RL16(avpkt->data + 3 + s->video_data_size);
1228+
s->decoding_map = buf + 3 + s->video_data_size + 2;
1229+
1230+
/* skip map contains 16 bits of information per 15 blocks, ish */
1231+
s->skip_map_size = AV_RL16(avpkt->data + 3 + s->video_data_size + 2 + s->decoding_map_size);
1232+
s->skip_map = buf + 3 + s->video_data_size + 2 + s->decoding_map_size + 2;
1233+
break;
1234+
1235+
case 0x11:
1236+
/* Format 0x11 has a decoding map and pixel data */
1237+
s->video_data_size = AV_RL16(avpkt->data + 1);
1238+
bytestream2_init(&s->stream_ptr, buf + 3, s->video_data_size);
1239+
1240+
/* decoding map contains 4 bits of information per 8x8 block */
1241+
s->decoding_map_size = AV_RL16(avpkt->data + 3 + s->video_data_size);
1242+
s->decoding_map = buf + 3 + s->video_data_size + 2;
1243+
1244+
/* compressed buffer needs to be large enough to at least hold an entire
1245+
* decoding map */
1246+
if (buf_size < s->decoding_map_size + 2)
1247+
return buf_size;
1248+
break;
1249+
1250+
default:
1251+
av_log(avctx, AV_LOG_ERROR, "Frame type 0x%02X unsupported\n", s->frame_format);
1252+
}
10141253

10151254
if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
10161255
return ret;
@@ -1026,7 +1265,14 @@ static int ipvideo_decode_frame(AVCodecContext *avctx,
10261265
}
10271266
}
10281267

1029-
ipvideo_decode_opcodes(s, frame);
1268+
if(s->frame_format == 0x06)
1269+
ipvideo_decode_format_06_opcodes(s, frame);
1270+
1271+
if(s->frame_format == 0x10)
1272+
ipvideo_decode_format_10_opcodes(s, frame);
1273+
1274+
if(s->frame_format == 0x11)
1275+
ipvideo_decode_format_11_opcodes(s, frame);
10301276

10311277
*got_frame = 1;
10321278

@@ -1046,6 +1292,8 @@ static av_cold int ipvideo_decode_end(AVCodecContext *avctx)
10461292

10471293
av_frame_free(&s->last_frame);
10481294
av_frame_free(&s->second_last_frame);
1295+
av_frame_free(&s->cur_decode_frame);
1296+
av_frame_free(&s->prev_decode_frame);
10491297

10501298
return 0;
10511299
}

0 commit comments

Comments
 (0)