libavcodec/ulti.c
Go to the documentation of this file.
00001 /*
00002  * IBM Ultimotion Video Decoder
00003  * Copyright (C) 2004 Konstantin Shishkov
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 
00031 #include "avcodec.h"
00032 #include "bytestream.h"
00033 
00034 #include "ulti_cb.h"
00035 
00036 typedef struct UltimotionDecodeContext {
00037     AVCodecContext *avctx;
00038     int width, height, blocks;
00039     AVFrame frame;
00040     const uint8_t *ulti_codebook;
00041     GetByteContext gb;
00042 } UltimotionDecodeContext;
00043 
00044 static av_cold int ulti_decode_init(AVCodecContext *avctx)
00045 {
00046     UltimotionDecodeContext *s = avctx->priv_data;
00047 
00048     s->avctx = avctx;
00049     s->width = avctx->width;
00050     s->height = avctx->height;
00051     s->blocks = (s->width / 8) * (s->height / 8);
00052     avctx->pix_fmt = PIX_FMT_YUV410P;
00053     avcodec_get_frame_defaults(&s->frame);
00054     avctx->coded_frame = (AVFrame*) &s->frame;
00055     s->ulti_codebook = ulti_codebook;
00056 
00057     return 0;
00058 }
00059 
00060 static av_cold int ulti_decode_end(AVCodecContext *avctx){
00061     UltimotionDecodeContext *s = avctx->priv_data;
00062     AVFrame *pic = &s->frame;
00063 
00064     if (pic->data[0])
00065         avctx->release_buffer(avctx, pic);
00066 
00067     return 0;
00068 }
00069 
00070 static const int block_coords[8] = // 4x4 block coords in 8x8 superblock
00071     { 0, 0, 0, 4, 4, 4, 4, 0};
00072 
00073 static const int angle_by_index[4] = { 0, 2, 6, 12};
00074 
00075 /* Lookup tables for luma and chroma - used by ulti_convert_yuv() */
00076 static const uint8_t ulti_lumas[64] =
00077     { 0x10, 0x13, 0x17, 0x1A, 0x1E, 0x21, 0x25, 0x28,
00078       0x2C, 0x2F, 0x33, 0x36, 0x3A, 0x3D, 0x41, 0x44,
00079       0x48, 0x4B, 0x4F, 0x52, 0x56, 0x59, 0x5C, 0x60,
00080       0x63, 0x67, 0x6A, 0x6E, 0x71, 0x75, 0x78, 0x7C,
00081       0x7F, 0x83, 0x86, 0x8A, 0x8D, 0x91, 0x94, 0x98,
00082       0x9B, 0x9F, 0xA2, 0xA5, 0xA9, 0xAC, 0xB0, 0xB3,
00083       0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8, 0xCC, 0xCF,
00084       0xD3, 0xD6, 0xDA, 0xDD, 0xE1, 0xE4, 0xE8, 0xEB};
00085 
00086 static const uint8_t ulti_chromas[16] =
00087     { 0x60, 0x67, 0x6D, 0x73, 0x7A, 0x80, 0x86, 0x8D,
00088       0x93, 0x99, 0xA0, 0xA6, 0xAC, 0xB3, 0xB9, 0xC0};
00089 
00090 /* convert Ultimotion YUV block (sixteen 6-bit Y samples and
00091  two 4-bit chroma samples) into standard YUV and put it into frame */
00092 static void ulti_convert_yuv(AVFrame *frame, int x, int y,
00093                              uint8_t *luma,int chroma)
00094 {
00095     uint8_t *y_plane, *cr_plane, *cb_plane;
00096     int i;
00097 
00098     y_plane = frame->data[0] + x + y * frame->linesize[0];
00099     cr_plane = frame->data[1] + (x / 4) + (y / 4) * frame->linesize[1];
00100     cb_plane = frame->data[2] + (x / 4) + (y / 4) * frame->linesize[2];
00101 
00102     cr_plane[0] = ulti_chromas[chroma >> 4];
00103 
00104     cb_plane[0] = ulti_chromas[chroma & 0xF];
00105 
00106 
00107     for(i = 0; i < 16; i++){
00108         y_plane[i & 3] = ulti_lumas[luma[i]];
00109         if((i & 3) == 3) { //next row
00110             y_plane += frame->linesize[0];
00111         }
00112     }
00113 }
00114 
00115 /* generate block like in MS Video1 */
00116 static void ulti_pattern(AVFrame *frame, int x, int y,
00117                          int f0, int f1, int Y0, int Y1, int chroma)
00118 {
00119     uint8_t Luma[16];
00120     int mask, i;
00121     for(mask = 0x80, i = 0; mask; mask >>= 1, i++) {
00122         if(f0 & mask)
00123             Luma[i] = Y1;
00124         else
00125             Luma[i] = Y0;
00126     }
00127 
00128     for(mask = 0x80, i = 8; mask; mask >>= 1, i++) {
00129         if(f1 & mask)
00130             Luma[i] = Y1;
00131         else
00132             Luma[i] = Y0;
00133     }
00134 
00135     ulti_convert_yuv(frame, x, y, Luma, chroma);
00136 }
00137 
00138 /* fill block with some gradient */
00139 static void ulti_grad(AVFrame *frame, int x, int y, uint8_t *Y, int chroma, int angle)
00140 {
00141     uint8_t Luma[16];
00142     if(angle & 8) { //reverse order
00143         int t;
00144         angle &= 0x7;
00145         t = Y[0];
00146         Y[0] = Y[3];
00147         Y[3] = t;
00148         t = Y[1];
00149         Y[1] = Y[2];
00150         Y[2] = t;
00151     }
00152     switch(angle){
00153     case 0:
00154         Luma[0]  = Y[0]; Luma[1]  = Y[1]; Luma[2]  = Y[2]; Luma[3]  = Y[3];
00155         Luma[4]  = Y[0]; Luma[5]  = Y[1]; Luma[6]  = Y[2]; Luma[7]  = Y[3];
00156         Luma[8]  = Y[0]; Luma[9]  = Y[1]; Luma[10] = Y[2]; Luma[11] = Y[3];
00157         Luma[12] = Y[0]; Luma[13] = Y[1]; Luma[14] = Y[2]; Luma[15] = Y[3];
00158         break;
00159     case 1:
00160         Luma[0]  = Y[1]; Luma[1]  = Y[2]; Luma[2]  = Y[3]; Luma[3]  = Y[3];
00161         Luma[4]  = Y[0]; Luma[5]  = Y[1]; Luma[6]  = Y[2]; Luma[7]  = Y[3];
00162         Luma[8]  = Y[0]; Luma[9]  = Y[1]; Luma[10] = Y[2]; Luma[11] = Y[3];
00163         Luma[12] = Y[0]; Luma[13] = Y[0]; Luma[14] = Y[1]; Luma[15] = Y[2];
00164         break;
00165     case 2:
00166         Luma[0]  = Y[1]; Luma[1]  = Y[2]; Luma[2]  = Y[3]; Luma[3]  = Y[3];
00167         Luma[4]  = Y[1]; Luma[5]  = Y[2]; Luma[6]  = Y[2]; Luma[7]  = Y[3];
00168         Luma[8]  = Y[0]; Luma[9]  = Y[1]; Luma[10] = Y[1]; Luma[11] = Y[2];
00169         Luma[12] = Y[0]; Luma[13] = Y[0]; Luma[14] = Y[1]; Luma[15] = Y[2];
00170         break;
00171     case 3:
00172         Luma[0]  = Y[2]; Luma[1]  = Y[3]; Luma[2]  = Y[3]; Luma[3]  = Y[3];
00173         Luma[4]  = Y[1]; Luma[5]  = Y[2]; Luma[6]  = Y[2]; Luma[7]  = Y[3];
00174         Luma[8]  = Y[0]; Luma[9]  = Y[1]; Luma[10] = Y[1]; Luma[11] = Y[2];
00175         Luma[12] = Y[0]; Luma[13] = Y[0]; Luma[14] = Y[0]; Luma[15] = Y[1];
00176         break;
00177     case 4:
00178         Luma[0]  = Y[3]; Luma[1]  = Y[3]; Luma[2]  = Y[3]; Luma[3]  = Y[3];
00179         Luma[4]  = Y[2]; Luma[5]  = Y[2]; Luma[6]  = Y[2]; Luma[7]  = Y[2];
00180         Luma[8]  = Y[1]; Luma[9]  = Y[1]; Luma[10] = Y[1]; Luma[11] = Y[1];
00181         Luma[12] = Y[0]; Luma[13] = Y[0]; Luma[14] = Y[0]; Luma[15] = Y[0];
00182         break;
00183     case 5:
00184         Luma[0]  = Y[3]; Luma[1]  = Y[3]; Luma[2]  = Y[3]; Luma[3]  = Y[2];
00185         Luma[4]  = Y[3]; Luma[5]  = Y[2]; Luma[6]  = Y[2]; Luma[7]  = Y[1];
00186         Luma[8]  = Y[2]; Luma[9]  = Y[1]; Luma[10] = Y[1]; Luma[11] = Y[0];
00187         Luma[12] = Y[1]; Luma[13] = Y[0]; Luma[14] = Y[0]; Luma[15] = Y[0];
00188         break;
00189     case 6:
00190         Luma[0]  = Y[3]; Luma[1]  = Y[3]; Luma[2]  = Y[2]; Luma[3]  = Y[2];
00191         Luma[4]  = Y[3]; Luma[5]  = Y[2]; Luma[6]  = Y[1]; Luma[7]  = Y[1];
00192         Luma[8]  = Y[2]; Luma[9]  = Y[2]; Luma[10] = Y[1]; Luma[11] = Y[0];
00193         Luma[12] = Y[1]; Luma[13] = Y[1]; Luma[14] = Y[0]; Luma[15] = Y[0];
00194         break;
00195     case 7:
00196         Luma[0]  = Y[3]; Luma[1]  = Y[3]; Luma[2]  = Y[2]; Luma[3]  = Y[1];
00197         Luma[4]  = Y[3]; Luma[5]  = Y[2]; Luma[6]  = Y[1]; Luma[7]  = Y[0];
00198         Luma[8]  = Y[3]; Luma[9]  = Y[2]; Luma[10] = Y[1]; Luma[11] = Y[0];
00199         Luma[12] = Y[2]; Luma[13] = Y[1]; Luma[14] = Y[0]; Luma[15] = Y[0];
00200         break;
00201     default:
00202         Luma[0]  = Y[0]; Luma[1]  = Y[0]; Luma[2]  = Y[1]; Luma[3]  = Y[1];
00203         Luma[4]  = Y[0]; Luma[5]  = Y[0]; Luma[6]  = Y[1]; Luma[7]  = Y[1];
00204         Luma[8]  = Y[2]; Luma[9]  = Y[2]; Luma[10] = Y[3]; Luma[11] = Y[3];
00205         Luma[12] = Y[2]; Luma[13] = Y[2]; Luma[14] = Y[3]; Luma[15] = Y[3];
00206         break;
00207     }
00208 
00209     ulti_convert_yuv(frame, x, y, Luma, chroma);
00210 }
00211 
00212 static int ulti_decode_frame(AVCodecContext *avctx,
00213                              void *data, int *data_size,
00214                              AVPacket *avpkt)
00215 {
00216     const uint8_t *buf = avpkt->data;
00217     int buf_size = avpkt->size;
00218     UltimotionDecodeContext *s=avctx->priv_data;
00219     int modifier = 0;
00220     int uniq = 0;
00221     int mode = 0;
00222     int blocks = 0;
00223     int done = 0;
00224     int x = 0, y = 0;
00225     int i;
00226     int skip;
00227     int tmp;
00228 
00229     s->frame.reference = 3;
00230     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00231     if (avctx->reget_buffer(avctx, &s->frame) < 0) {
00232         av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00233         return -1;
00234     }
00235 
00236     bytestream2_init(&s->gb, buf, buf_size);
00237 
00238     while(!done) {
00239         int idx;
00240         if(blocks >= s->blocks || y >= s->height)
00241             break;//all blocks decoded
00242 
00243         if (bytestream2_get_bytes_left(&s->gb) < 1)
00244             goto err;
00245         idx = bytestream2_get_byteu(&s->gb);
00246         if((idx & 0xF8) == 0x70) {
00247             switch(idx) {
00248             case 0x70: //change modifier
00249                 modifier = bytestream2_get_byte(&s->gb);
00250                 if(modifier>1)
00251                     av_log(avctx, AV_LOG_INFO, "warning: modifier must be 0 or 1, got %i\n", modifier);
00252                 break;
00253             case 0x71: // set uniq flag
00254                 uniq = 1;
00255                 break;
00256             case 0x72: //toggle mode
00257                 mode = !mode;
00258                 break;
00259             case 0x73: //end-of-frame
00260                 done = 1;
00261                 break;
00262             case 0x74: //skip some blocks
00263                 skip = bytestream2_get_byte(&s->gb);
00264                 if ((blocks + skip) >= s->blocks)
00265                     break;
00266                 blocks += skip;
00267                 x += skip * 8;
00268                 while(x >= s->width) {
00269                     x -= s->width;
00270                     y += 8;
00271                 }
00272                 break;
00273             default:
00274                 av_log(avctx, AV_LOG_INFO, "warning: unknown escape 0x%02X\n", idx);
00275             }
00276         } else { //handle one block
00277             int code;
00278             int cf;
00279             int angle = 0;
00280             uint8_t Y[4]; // luma samples of block
00281             int tx = 0, ty = 0; //coords of subblock
00282             int chroma = 0;
00283             if (mode || uniq) {
00284                 uniq = 0;
00285                 cf = 1;
00286                 chroma = 0;
00287             } else {
00288                 cf = 0;
00289                 if (idx) {
00290                     chroma = bytestream2_get_byte(&s->gb);
00291                 }
00292             }
00293             for (i = 0; i < 4; i++) { // for every subblock
00294                 code = (idx >> (6 - i*2)) & 3; //extract 2 bits
00295                 if(!code) //skip subblock
00296                     continue;
00297                 if(cf) {
00298                     chroma = bytestream2_get_byte(&s->gb);
00299                 }
00300                 tx = x + block_coords[i * 2];
00301                 ty = y + block_coords[(i * 2) + 1];
00302                 switch(code) {
00303                 case 1:
00304                     tmp = bytestream2_get_byte(&s->gb);
00305 
00306                     angle = angle_by_index[(tmp >> 6) & 0x3];
00307 
00308                     Y[0] = tmp & 0x3F;
00309                     Y[1] = Y[0];
00310 
00311                     if (angle) {
00312                         Y[2] = Y[0]+1;
00313                         if (Y[2] > 0x3F)
00314                             Y[2] = 0x3F;
00315                         Y[3] = Y[2];
00316                     } else {
00317                         Y[2] = Y[0];
00318                         Y[3] = Y[0];
00319                     }
00320                     break;
00321 
00322                 case 2:
00323                     if (modifier) { // unpack four luma samples
00324                         tmp = bytestream2_get_be24(&s->gb);
00325 
00326                         Y[0] = (tmp >> 18) & 0x3F;
00327                         Y[1] = (tmp >> 12) & 0x3F;
00328                         Y[2] = (tmp >> 6) & 0x3F;
00329                         Y[3] = tmp & 0x3F;
00330                         angle = 16;
00331                     } else { // retrieve luma samples from codebook
00332                         tmp = bytestream2_get_be16(&s->gb);
00333 
00334                         angle = (tmp >> 12) & 0xF;
00335                         tmp &= 0xFFF;
00336                         tmp <<= 2;
00337                         Y[0] = s->ulti_codebook[tmp];
00338                         Y[1] = s->ulti_codebook[tmp + 1];
00339                         Y[2] = s->ulti_codebook[tmp + 2];
00340                         Y[3] = s->ulti_codebook[tmp + 3];
00341                     }
00342                     break;
00343 
00344                 case 3:
00345                     if (modifier) { // all 16 luma samples
00346                         uint8_t Luma[16];
00347 
00348                         if (bytestream2_get_bytes_left(&s->gb) < 12)
00349                             goto err;
00350                         tmp = bytestream2_get_be24u(&s->gb);
00351                         Luma[0] = (tmp >> 18) & 0x3F;
00352                         Luma[1] = (tmp >> 12) & 0x3F;
00353                         Luma[2] = (tmp >> 6) & 0x3F;
00354                         Luma[3] = tmp & 0x3F;
00355 
00356                         tmp = bytestream2_get_be24u(&s->gb);
00357                         Luma[4] = (tmp >> 18) & 0x3F;
00358                         Luma[5] = (tmp >> 12) & 0x3F;
00359                         Luma[6] = (tmp >> 6) & 0x3F;
00360                         Luma[7] = tmp & 0x3F;
00361 
00362                         tmp = bytestream2_get_be24u(&s->gb);
00363                         Luma[8] = (tmp >> 18) & 0x3F;
00364                         Luma[9] = (tmp >> 12) & 0x3F;
00365                         Luma[10] = (tmp >> 6) & 0x3F;
00366                         Luma[11] = tmp & 0x3F;
00367 
00368                         tmp = bytestream2_get_be24u(&s->gb);
00369                         Luma[12] = (tmp >> 18) & 0x3F;
00370                         Luma[13] = (tmp >> 12) & 0x3F;
00371                         Luma[14] = (tmp >> 6) & 0x3F;
00372                         Luma[15] = tmp & 0x3F;
00373 
00374                         ulti_convert_yuv(&s->frame, tx, ty, Luma, chroma);
00375                     } else {
00376                         if (bytestream2_get_bytes_left(&s->gb) < 4)
00377                             goto err;
00378                         tmp = bytestream2_get_byteu(&s->gb);
00379                         if(tmp & 0x80) {
00380                             angle = (tmp >> 4) & 0x7;
00381                             tmp = (tmp << 8) + bytestream2_get_byteu(&s->gb);
00382                             Y[0] = (tmp >> 6) & 0x3F;
00383                             Y[1] = tmp & 0x3F;
00384                             Y[2] = bytestream2_get_byteu(&s->gb) & 0x3F;
00385                             Y[3] = bytestream2_get_byteu(&s->gb) & 0x3F;
00386                             ulti_grad(&s->frame, tx, ty, Y, chroma, angle); //draw block
00387                         } else { // some patterns
00388                             int f0, f1;
00389                             f0 = bytestream2_get_byteu(&s->gb);
00390                             f1 = tmp;
00391                             Y[0] = bytestream2_get_byteu(&s->gb) & 0x3F;
00392                             Y[1] = bytestream2_get_byteu(&s->gb) & 0x3F;
00393                             ulti_pattern(&s->frame, tx, ty, f1, f0, Y[0], Y[1], chroma);
00394                         }
00395                     }
00396                     break;
00397                 }
00398                 if(code != 3)
00399                     ulti_grad(&s->frame, tx, ty, Y, chroma, angle); // draw block
00400             }
00401             blocks++;
00402                 x += 8;
00403             if(x >= s->width) {
00404                 x = 0;
00405                 y += 8;
00406             }
00407         }
00408     }
00409 
00410     *data_size=sizeof(AVFrame);
00411     *(AVFrame*)data= s->frame;
00412 
00413     return buf_size;
00414 
00415 err:
00416     av_log(avctx, AV_LOG_ERROR,
00417            "Insufficient data\n");
00418     return AVERROR_INVALIDDATA;
00419 }
00420 
00421 AVCodec ff_ulti_decoder = {
00422     .name           = "ultimotion",
00423     .type           = AVMEDIA_TYPE_VIDEO,
00424     .id             = CODEC_ID_ULTI,
00425     .priv_data_size = sizeof(UltimotionDecodeContext),
00426     .init           = ulti_decode_init,
00427     .close          = ulti_decode_end,
00428     .decode         = ulti_decode_frame,
00429     .capabilities   = CODEC_CAP_DR1,
00430     .long_name = NULL_IF_CONFIG_SMALL("IBM UltiMotion"),
00431 };
00432