1/* 2 * IBM Ultimotion Video Decoder 3 * Copyright (C) 2004 Konstantin Shishkov 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * IBM Ultimotion Video Decoder. 25 */ 26 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30 31#include "avcodec.h" 32#include "bytestream.h" 33#include "codec_internal.h" 34#include "internal.h" 35 36#include "ulti_cb.h" 37 38typedef struct UltimotionDecodeContext { 39 AVCodecContext *avctx; 40 int width, height, blocks; 41 AVFrame *frame; 42 const uint8_t *ulti_codebook; 43 GetByteContext gb; 44} UltimotionDecodeContext; 45 46static av_cold int ulti_decode_init(AVCodecContext *avctx) 47{ 48 UltimotionDecodeContext *s = avctx->priv_data; 49 50 s->avctx = avctx; 51 s->width = avctx->width; 52 s->height = avctx->height; 53 s->blocks = (s->width / 8) * (s->height / 8); 54 if (s->blocks == 0) 55 return AVERROR_INVALIDDATA; 56 avctx->pix_fmt = AV_PIX_FMT_YUV410P; 57 s->ulti_codebook = ulti_codebook; 58 59 s->frame = av_frame_alloc(); 60 if (!s->frame) 61 return AVERROR(ENOMEM); 62 63 return 0; 64} 65 66static av_cold int ulti_decode_end(AVCodecContext *avctx) 67{ 68 UltimotionDecodeContext *s = avctx->priv_data; 69 70 av_frame_free(&s->frame); 71 72 return 0; 73} 74 75static const int block_coords[8] = // 4x4 block coords in 8x8 superblock 76 { 0, 0, 0, 4, 4, 4, 4, 0}; 77 78static const int angle_by_index[4] = { 0, 2, 6, 12}; 79 80/* Lookup tables for luma and chroma - used by ulti_convert_yuv() */ 81static const uint8_t ulti_lumas[64] = 82 { 0x10, 0x13, 0x17, 0x1A, 0x1E, 0x21, 0x25, 0x28, 83 0x2C, 0x2F, 0x33, 0x36, 0x3A, 0x3D, 0x41, 0x44, 84 0x48, 0x4B, 0x4F, 0x52, 0x56, 0x59, 0x5C, 0x60, 85 0x63, 0x67, 0x6A, 0x6E, 0x71, 0x75, 0x78, 0x7C, 86 0x7F, 0x83, 0x86, 0x8A, 0x8D, 0x91, 0x94, 0x98, 87 0x9B, 0x9F, 0xA2, 0xA5, 0xA9, 0xAC, 0xB0, 0xB3, 88 0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8, 0xCC, 0xCF, 89 0xD3, 0xD6, 0xDA, 0xDD, 0xE1, 0xE4, 0xE8, 0xEB}; 90 91static const uint8_t ulti_chromas[16] = 92 { 0x60, 0x67, 0x6D, 0x73, 0x7A, 0x80, 0x86, 0x8D, 93 0x93, 0x99, 0xA0, 0xA6, 0xAC, 0xB3, 0xB9, 0xC0}; 94 95/* convert Ultimotion YUV block (sixteen 6-bit Y samples and 96 two 4-bit chroma samples) into standard YUV and put it into frame */ 97static void ulti_convert_yuv(AVFrame *frame, int x, int y, 98 uint8_t *luma,int chroma) 99{ 100 uint8_t *y_plane, *cr_plane, *cb_plane; 101 int i; 102 103 y_plane = frame->data[0] + x + y * frame->linesize[0]; 104 cr_plane = frame->data[1] + (x / 4) + (y / 4) * frame->linesize[1]; 105 cb_plane = frame->data[2] + (x / 4) + (y / 4) * frame->linesize[2]; 106 107 cr_plane[0] = ulti_chromas[chroma >> 4]; 108 109 cb_plane[0] = ulti_chromas[chroma & 0xF]; 110 111 112 for(i = 0; i < 16; i++){ 113 y_plane[i & 3] = ulti_lumas[luma[i]]; 114 if((i & 3) == 3) { //next row 115 y_plane += frame->linesize[0]; 116 } 117 } 118} 119 120/* generate block like in MS Video1 */ 121static void ulti_pattern(AVFrame *frame, int x, int y, 122 int f0, int f1, int Y0, int Y1, int chroma) 123{ 124 uint8_t Luma[16]; 125 int mask, i; 126 for(mask = 0x80, i = 0; mask; mask >>= 1, i++) { 127 if(f0 & mask) 128 Luma[i] = Y1; 129 else 130 Luma[i] = Y0; 131 } 132 133 for(mask = 0x80, i = 8; mask; mask >>= 1, i++) { 134 if(f1 & mask) 135 Luma[i] = Y1; 136 else 137 Luma[i] = Y0; 138 } 139 140 ulti_convert_yuv(frame, x, y, Luma, chroma); 141} 142 143/* fill block with some gradient */ 144static void ulti_grad(AVFrame *frame, int x, int y, uint8_t *Y, int chroma, int angle) 145{ 146 uint8_t Luma[16]; 147 if(angle & 8) { //reverse order 148 int t; 149 angle &= 0x7; 150 t = Y[0]; 151 Y[0] = Y[3]; 152 Y[3] = t; 153 t = Y[1]; 154 Y[1] = Y[2]; 155 Y[2] = t; 156 } 157 switch(angle){ 158 case 0: 159 Luma[0] = Y[0]; Luma[1] = Y[1]; Luma[2] = Y[2]; Luma[3] = Y[3]; 160 Luma[4] = Y[0]; Luma[5] = Y[1]; Luma[6] = Y[2]; Luma[7] = Y[3]; 161 Luma[8] = Y[0]; Luma[9] = Y[1]; Luma[10] = Y[2]; Luma[11] = Y[3]; 162 Luma[12] = Y[0]; Luma[13] = Y[1]; Luma[14] = Y[2]; Luma[15] = Y[3]; 163 break; 164 case 1: 165 Luma[0] = Y[1]; Luma[1] = Y[2]; Luma[2] = Y[3]; Luma[3] = Y[3]; 166 Luma[4] = Y[0]; Luma[5] = Y[1]; Luma[6] = Y[2]; Luma[7] = Y[3]; 167 Luma[8] = Y[0]; Luma[9] = Y[1]; Luma[10] = Y[2]; Luma[11] = Y[3]; 168 Luma[12] = Y[0]; Luma[13] = Y[0]; Luma[14] = Y[1]; Luma[15] = Y[2]; 169 break; 170 case 2: 171 Luma[0] = Y[1]; Luma[1] = Y[2]; Luma[2] = Y[3]; Luma[3] = Y[3]; 172 Luma[4] = Y[1]; Luma[5] = Y[2]; Luma[6] = Y[2]; Luma[7] = Y[3]; 173 Luma[8] = Y[0]; Luma[9] = Y[1]; Luma[10] = Y[1]; Luma[11] = Y[2]; 174 Luma[12] = Y[0]; Luma[13] = Y[0]; Luma[14] = Y[1]; Luma[15] = Y[2]; 175 break; 176 case 3: 177 Luma[0] = Y[2]; Luma[1] = Y[3]; Luma[2] = Y[3]; Luma[3] = Y[3]; 178 Luma[4] = Y[1]; Luma[5] = Y[2]; Luma[6] = Y[2]; Luma[7] = Y[3]; 179 Luma[8] = Y[0]; Luma[9] = Y[1]; Luma[10] = Y[1]; Luma[11] = Y[2]; 180 Luma[12] = Y[0]; Luma[13] = Y[0]; Luma[14] = Y[0]; Luma[15] = Y[1]; 181 break; 182 case 4: 183 Luma[0] = Y[3]; Luma[1] = Y[3]; Luma[2] = Y[3]; Luma[3] = Y[3]; 184 Luma[4] = Y[2]; Luma[5] = Y[2]; Luma[6] = Y[2]; Luma[7] = Y[2]; 185 Luma[8] = Y[1]; Luma[9] = Y[1]; Luma[10] = Y[1]; Luma[11] = Y[1]; 186 Luma[12] = Y[0]; Luma[13] = Y[0]; Luma[14] = Y[0]; Luma[15] = Y[0]; 187 break; 188 case 5: 189 Luma[0] = Y[3]; Luma[1] = Y[3]; Luma[2] = Y[3]; Luma[3] = Y[2]; 190 Luma[4] = Y[3]; Luma[5] = Y[2]; Luma[6] = Y[2]; Luma[7] = Y[1]; 191 Luma[8] = Y[2]; Luma[9] = Y[1]; Luma[10] = Y[1]; Luma[11] = Y[0]; 192 Luma[12] = Y[1]; Luma[13] = Y[0]; Luma[14] = Y[0]; Luma[15] = Y[0]; 193 break; 194 case 6: 195 Luma[0] = Y[3]; Luma[1] = Y[3]; Luma[2] = Y[2]; Luma[3] = Y[2]; 196 Luma[4] = Y[3]; Luma[5] = Y[2]; Luma[6] = Y[1]; Luma[7] = Y[1]; 197 Luma[8] = Y[2]; Luma[9] = Y[2]; Luma[10] = Y[1]; Luma[11] = Y[0]; 198 Luma[12] = Y[1]; Luma[13] = Y[1]; Luma[14] = Y[0]; Luma[15] = Y[0]; 199 break; 200 case 7: 201 Luma[0] = Y[3]; Luma[1] = Y[3]; Luma[2] = Y[2]; Luma[3] = Y[1]; 202 Luma[4] = Y[3]; Luma[5] = Y[2]; Luma[6] = Y[1]; Luma[7] = Y[0]; 203 Luma[8] = Y[3]; Luma[9] = Y[2]; Luma[10] = Y[1]; Luma[11] = Y[0]; 204 Luma[12] = Y[2]; Luma[13] = Y[1]; Luma[14] = Y[0]; Luma[15] = Y[0]; 205 break; 206 default: 207 Luma[0] = Y[0]; Luma[1] = Y[0]; Luma[2] = Y[1]; Luma[3] = Y[1]; 208 Luma[4] = Y[0]; Luma[5] = Y[0]; Luma[6] = Y[1]; Luma[7] = Y[1]; 209 Luma[8] = Y[2]; Luma[9] = Y[2]; Luma[10] = Y[3]; Luma[11] = Y[3]; 210 Luma[12] = Y[2]; Luma[13] = Y[2]; Luma[14] = Y[3]; Luma[15] = Y[3]; 211 break; 212 } 213 214 ulti_convert_yuv(frame, x, y, Luma, chroma); 215} 216 217static int ulti_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 218 int *got_frame, AVPacket *avpkt) 219{ 220 const uint8_t *buf = avpkt->data; 221 int buf_size = avpkt->size; 222 UltimotionDecodeContext *s=avctx->priv_data; 223 int modifier = 0; 224 int uniq = 0; 225 int mode = 0; 226 int blocks = 0; 227 int done = 0; 228 int x = 0, y = 0; 229 int i, ret; 230 int skip; 231 int tmp; 232 233 if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) 234 return ret; 235 236 bytestream2_init(&s->gb, buf, buf_size); 237 238 while(!done) { 239 int idx; 240 if(blocks >= s->blocks || y >= s->height) 241 break;//all blocks decoded 242 243 if (bytestream2_get_bytes_left(&s->gb) < 1) 244 goto err; 245 idx = bytestream2_get_byteu(&s->gb); 246 if((idx & 0xF8) == 0x70) { 247 switch(idx) { 248 case 0x70: //change modifier 249 modifier = bytestream2_get_byte(&s->gb); 250 if(modifier>1) 251 av_log(avctx, AV_LOG_INFO, "warning: modifier must be 0 or 1, got %i\n", modifier); 252 break; 253 case 0x71: // set uniq flag 254 uniq = 1; 255 break; 256 case 0x72: //toggle mode 257 mode = !mode; 258 break; 259 case 0x73: //end-of-frame 260 done = 1; 261 break; 262 case 0x74: //skip some blocks 263 skip = bytestream2_get_byte(&s->gb); 264 if ((blocks + skip) >= s->blocks) 265 break; 266 blocks += skip; 267 x += skip * 8; 268 while(x >= s->width) { 269 x -= s->width; 270 y += 8; 271 } 272 break; 273 default: 274 av_log(avctx, AV_LOG_INFO, "warning: unknown escape 0x%02X\n", idx); 275 } 276 } else { //handle one block 277 int code; 278 int cf; 279 int angle = 0; 280 uint8_t Y[4]; // luma samples of block 281 int tx = 0, ty = 0; //coords of subblock 282 int chroma = 0; 283 if (mode || uniq) { 284 uniq = 0; 285 cf = 1; 286 chroma = 0; 287 } else { 288 cf = 0; 289 if (idx) { 290 chroma = bytestream2_get_byte(&s->gb); 291 } 292 } 293 for (i = 0; i < 4; i++) { // for every subblock 294 code = (idx >> (6 - i*2)) & 3; //extract 2 bits 295 if(!code) //skip subblock 296 continue; 297 if(cf) { 298 chroma = bytestream2_get_byte(&s->gb); 299 } 300 tx = x + block_coords[i * 2]; 301 ty = y + block_coords[(i * 2) + 1]; 302 switch(code) { 303 case 1: 304 tmp = bytestream2_get_byte(&s->gb); 305 306 angle = angle_by_index[(tmp >> 6) & 0x3]; 307 308 Y[0] = tmp & 0x3F; 309 Y[1] = Y[0]; 310 311 if (angle) { 312 Y[2] = Y[0]+1; 313 if (Y[2] > 0x3F) 314 Y[2] = 0x3F; 315 Y[3] = Y[2]; 316 } else { 317 Y[2] = Y[0]; 318 Y[3] = Y[0]; 319 } 320 break; 321 322 case 2: 323 if (modifier) { // unpack four luma samples 324 tmp = bytestream2_get_be24(&s->gb); 325 326 Y[0] = (tmp >> 18) & 0x3F; 327 Y[1] = (tmp >> 12) & 0x3F; 328 Y[2] = (tmp >> 6) & 0x3F; 329 Y[3] = tmp & 0x3F; 330 angle = 16; 331 } else { // retrieve luma samples from codebook 332 tmp = bytestream2_get_be16(&s->gb); 333 334 angle = (tmp >> 12) & 0xF; 335 tmp &= 0xFFF; 336 tmp <<= 2; 337 Y[0] = s->ulti_codebook[tmp]; 338 Y[1] = s->ulti_codebook[tmp + 1]; 339 Y[2] = s->ulti_codebook[tmp + 2]; 340 Y[3] = s->ulti_codebook[tmp + 3]; 341 } 342 break; 343 344 case 3: 345 if (modifier) { // all 16 luma samples 346 uint8_t Luma[16]; 347 348 if (bytestream2_get_bytes_left(&s->gb) < 12) 349 goto err; 350 tmp = bytestream2_get_be24u(&s->gb); 351 Luma[0] = (tmp >> 18) & 0x3F; 352 Luma[1] = (tmp >> 12) & 0x3F; 353 Luma[2] = (tmp >> 6) & 0x3F; 354 Luma[3] = tmp & 0x3F; 355 356 tmp = bytestream2_get_be24u(&s->gb); 357 Luma[4] = (tmp >> 18) & 0x3F; 358 Luma[5] = (tmp >> 12) & 0x3F; 359 Luma[6] = (tmp >> 6) & 0x3F; 360 Luma[7] = tmp & 0x3F; 361 362 tmp = bytestream2_get_be24u(&s->gb); 363 Luma[8] = (tmp >> 18) & 0x3F; 364 Luma[9] = (tmp >> 12) & 0x3F; 365 Luma[10] = (tmp >> 6) & 0x3F; 366 Luma[11] = tmp & 0x3F; 367 368 tmp = bytestream2_get_be24u(&s->gb); 369 Luma[12] = (tmp >> 18) & 0x3F; 370 Luma[13] = (tmp >> 12) & 0x3F; 371 Luma[14] = (tmp >> 6) & 0x3F; 372 Luma[15] = tmp & 0x3F; 373 374 ulti_convert_yuv(s->frame, tx, ty, Luma, chroma); 375 } else { 376 if (bytestream2_get_bytes_left(&s->gb) < 4) 377 goto err; 378 tmp = bytestream2_get_byteu(&s->gb); 379 if(tmp & 0x80) { 380 angle = (tmp >> 4) & 0x7; 381 tmp = (tmp << 8) + bytestream2_get_byteu(&s->gb); 382 Y[0] = (tmp >> 6) & 0x3F; 383 Y[1] = tmp & 0x3F; 384 Y[2] = bytestream2_get_byteu(&s->gb) & 0x3F; 385 Y[3] = bytestream2_get_byteu(&s->gb) & 0x3F; 386 ulti_grad(s->frame, tx, ty, Y, chroma, angle); //draw block 387 } else { // some patterns 388 int f0 = tmp; 389 int f1 = bytestream2_get_byteu(&s->gb); 390 Y[0] = bytestream2_get_byteu(&s->gb) & 0x3F; 391 Y[1] = bytestream2_get_byteu(&s->gb) & 0x3F; 392 ulti_pattern(s->frame, tx, ty, f0, f1, Y[0], Y[1], chroma); 393 } 394 } 395 break; 396 } 397 if(code != 3) 398 ulti_grad(s->frame, tx, ty, Y, chroma, angle); // draw block 399 } 400 blocks++; 401 x += 8; 402 if(x >= s->width) { 403 x = 0; 404 y += 8; 405 } 406 } 407 } 408 409 *got_frame = 1; 410 if ((ret = av_frame_ref(rframe, s->frame)) < 0) 411 return ret; 412 413 return buf_size; 414 415err: 416 av_log(avctx, AV_LOG_ERROR, 417 "Insufficient data\n"); 418 return AVERROR_INVALIDDATA; 419} 420 421const FFCodec ff_ulti_decoder = { 422 .p.name = "ultimotion", 423 .p.long_name = NULL_IF_CONFIG_SMALL("IBM UltiMotion"), 424 .p.type = AVMEDIA_TYPE_VIDEO, 425 .p.id = AV_CODEC_ID_ULTI, 426 .priv_data_size = sizeof(UltimotionDecodeContext), 427 .init = ulti_decode_init, 428 .close = ulti_decode_end, 429 FF_CODEC_DECODE_CB(ulti_decode_frame), 430 .p.capabilities = AV_CODEC_CAP_DR1, 431 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 432}; 433