• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

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