libavcodec/nuv.c
Go to the documentation of this file.
00001 /*
00002  * NuppelVideo decoder
00003  * Copyright (c) 2006 Reimar Doeffinger
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 #include <stdio.h>
00022 #include <stdlib.h>
00023 
00024 #include "libavutil/bswap.h"
00025 #include "libavutil/lzo.h"
00026 #include "libavutil/imgutils.h"
00027 #include "avcodec.h"
00028 #include "dsputil.h"
00029 #include "rtjpeg.h"
00030 
00031 typedef struct {
00032     AVFrame pic;
00033     int codec_frameheader;
00034     int quality;
00035     int width, height;
00036     unsigned int decomp_size;
00037     unsigned char* decomp_buf;
00038     uint32_t lq[64], cq[64];
00039     RTJpegContext rtj;
00040     DSPContext dsp;
00041 } NuvContext;
00042 
00043 static const uint8_t fallback_lquant[] = {
00044     16,  11,  10,  16,  24,  40,  51,  61,
00045     12,  12,  14,  19,  26,  58,  60,  55,
00046     14,  13,  16,  24,  40,  57,  69,  56,
00047     14,  17,  22,  29,  51,  87,  80,  62,
00048     18,  22,  37,  56,  68, 109, 103,  77,
00049     24,  35,  55,  64,  81, 104, 113,  92,
00050     49,  64,  78,  87, 103, 121, 120, 101,
00051     72,  92,  95,  98, 112, 100, 103,  99
00052 };
00053 
00054 static const uint8_t fallback_cquant[] = {
00055     17, 18, 24, 47, 99, 99, 99, 99,
00056     18, 21, 26, 66, 99, 99, 99, 99,
00057     24, 26, 56, 99, 99, 99, 99, 99,
00058     47, 66, 99, 99, 99, 99, 99, 99,
00059     99, 99, 99, 99, 99, 99, 99, 99,
00060     99, 99, 99, 99, 99, 99, 99, 99,
00061     99, 99, 99, 99, 99, 99, 99, 99,
00062     99, 99, 99, 99, 99, 99, 99, 99
00063 };
00064 
00072 static void copy_frame(AVFrame *f, const uint8_t *src,
00073                        int width, int height) {
00074     AVPicture pic;
00075     avpicture_fill(&pic, src, PIX_FMT_YUV420P, width, height);
00076     av_picture_copy((AVPicture *)f, &pic, PIX_FMT_YUV420P, width, height);
00077 }
00078 
00082 static int get_quant(AVCodecContext *avctx, NuvContext *c,
00083                      const uint8_t *buf, int size) {
00084     int i;
00085     if (size < 2 * 64 * 4) {
00086         av_log(avctx, AV_LOG_ERROR, "insufficient rtjpeg quant data\n");
00087         return AVERROR_INVALIDDATA;
00088     }
00089     for (i = 0; i < 64; i++, buf += 4)
00090         c->lq[i] = AV_RL32(buf);
00091     for (i = 0; i < 64; i++, buf += 4)
00092         c->cq[i] = AV_RL32(buf);
00093     return 0;
00094 }
00095 
00099 static void get_quant_quality(NuvContext *c, int quality) {
00100     int i;
00101     quality = FFMAX(quality, 1);
00102     for (i = 0; i < 64; i++) {
00103         c->lq[i] = (fallback_lquant[i] << 7) / quality;
00104         c->cq[i] = (fallback_cquant[i] << 7) / quality;
00105     }
00106 }
00107 
00108 static int codec_reinit(AVCodecContext *avctx, int width, int height, int quality) {
00109     NuvContext *c = avctx->priv_data;
00110     int ret;
00111 
00112     width  = FFALIGN(width,  2);
00113     height = FFALIGN(height, 2);
00114     if (quality >= 0)
00115         get_quant_quality(c, quality);
00116     if (width != c->width || height != c->height) {
00117         void *ptr;
00118         if ((ret = av_image_check_size(height, width, 0, avctx)) < 0)
00119             return ret;
00120         avctx->width = c->width = width;
00121         avctx->height = c->height = height;
00122         ptr = av_fast_realloc(c->decomp_buf, &c->decomp_size,
00123                               c->height * c->width * 3 / 2 +
00124                               FF_INPUT_BUFFER_PADDING_SIZE +
00125                               RTJPEG_HEADER_SIZE);
00126         if (!ptr) {
00127             av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
00128             return AVERROR(ENOMEM);
00129         } else
00130             c->decomp_buf = ptr;
00131         rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00132         if (c->pic.data[0])
00133             avctx->release_buffer(avctx, &c->pic);
00134     } else if (quality != c->quality)
00135         rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00136     return 0;
00137 }
00138 
00139 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
00140                         AVPacket *avpkt) {
00141     const uint8_t *buf = avpkt->data;
00142     int buf_size = avpkt->size;
00143     NuvContext *c = avctx->priv_data;
00144     AVFrame *picture = data;
00145     int orig_size = buf_size;
00146     int keyframe;
00147     int result;
00148     int ret;
00149     enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1',
00150           NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3',
00151           NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype;
00152 
00153     if (buf_size < 12) {
00154         av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
00155         return AVERROR_INVALIDDATA;
00156     }
00157 
00158     // codec data (rtjpeg quant tables)
00159     if (buf[0] == 'D' && buf[1] == 'R') {
00160         int ret;
00161         // skip rest of the frameheader.
00162         buf = &buf[12];
00163         buf_size -= 12;
00164         ret = get_quant(avctx, c, buf, buf_size);
00165         if (ret < 0)
00166             return ret;
00167         rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00168         return orig_size;
00169     }
00170 
00171     if (buf[0] != 'V' || buf_size < 12) {
00172         av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
00173         return AVERROR_INVALIDDATA;
00174     }
00175     comptype = buf[1];
00176     switch (comptype) {
00177         case NUV_RTJPEG_IN_LZO:
00178         case NUV_RTJPEG:
00179             keyframe = !buf[2]; break;
00180         case NUV_COPY_LAST:
00181             keyframe = 0; break;
00182         default:
00183             keyframe = 1; break;
00184     }
00185     // skip rest of the frameheader.
00186     buf = &buf[12];
00187     buf_size -= 12;
00188     if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
00189         int outlen = c->decomp_size - FF_INPUT_BUFFER_PADDING_SIZE;
00190         int inlen  = buf_size;
00191         if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) {
00192             av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
00193             return AVERROR_INVALIDDATA;
00194         }
00195         buf = c->decomp_buf;
00196         buf_size = outlen;
00197     }
00198     if (c->codec_frameheader) {
00199         int w, h, q;
00200         if (buf_size < RTJPEG_HEADER_SIZE || buf[4] != RTJPEG_HEADER_SIZE ||
00201             buf[5] != RTJPEG_FILE_VERSION) {
00202             av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n");
00203             return AVERROR_INVALIDDATA;
00204         }
00205         w = AV_RL16(&buf[6]);
00206         h = AV_RL16(&buf[8]);
00207         q = buf[10];
00208         if ((result = codec_reinit(avctx, w, h, q)) < 0)
00209             return result;
00210         if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO)
00211             buf = c->decomp_buf;
00212         buf = &buf[RTJPEG_HEADER_SIZE];
00213         buf_size -= RTJPEG_HEADER_SIZE;
00214     }
00215 
00216     if (keyframe && c->pic.data[0])
00217         avctx->release_buffer(avctx, &c->pic);
00218     c->pic.reference = 3;
00219     c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE |
00220                           FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00221     result = avctx->reget_buffer(avctx, &c->pic);
00222     if (result < 0) {
00223         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00224         return result;
00225     }
00226 
00227     c->pic.pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
00228     c->pic.key_frame = keyframe;
00229     // decompress/copy/whatever data
00230     switch (comptype) {
00231         case NUV_LZO:
00232         case NUV_UNCOMPRESSED: {
00233             int height = c->height;
00234             if (buf_size < c->width * height * 3 / 2) {
00235                 av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
00236                 height = buf_size / c->width / 3 * 2;
00237             }
00238             copy_frame(&c->pic, buf, c->width, height);
00239             break;
00240         }
00241         case NUV_RTJPEG_IN_LZO:
00242         case NUV_RTJPEG: {
00243             ret = rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size);
00244             if (ret < 0)
00245                 return ret;
00246             break;
00247         }
00248         case NUV_BLACK: {
00249             memset(c->pic.data[0], 0, c->width * c->height);
00250             memset(c->pic.data[1], 128, c->width * c->height / 4);
00251             memset(c->pic.data[2], 128, c->width * c->height / 4);
00252             break;
00253         }
00254         case NUV_COPY_LAST: {
00255             /* nothing more to do here */
00256             break;
00257         }
00258         default:
00259             av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
00260             return AVERROR_INVALIDDATA;
00261     }
00262 
00263     *picture = c->pic;
00264     *data_size = sizeof(AVFrame);
00265     return orig_size;
00266 }
00267 
00268 static av_cold int decode_init(AVCodecContext *avctx) {
00269     NuvContext *c = avctx->priv_data;
00270     int ret;
00271 
00272     avctx->pix_fmt = PIX_FMT_YUV420P;
00273     c->pic.data[0] = NULL;
00274     c->decomp_buf = NULL;
00275     c->quality = -1;
00276     c->width = 0;
00277     c->height = 0;
00278     c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G');
00279     if (avctx->extradata_size)
00280         get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
00281     dsputil_init(&c->dsp, avctx);
00282     if ((ret = codec_reinit(avctx, avctx->width, avctx->height, -1)) < 0)
00283         return ret;
00284     return 0;
00285 }
00286 
00287 static av_cold int decode_end(AVCodecContext *avctx) {
00288     NuvContext *c = avctx->priv_data;
00289     av_freep(&c->decomp_buf);
00290     if (c->pic.data[0])
00291         avctx->release_buffer(avctx, &c->pic);
00292     return 0;
00293 }
00294 
00295 AVCodec ff_nuv_decoder = {
00296     .name           = "nuv",
00297     .type           = AVMEDIA_TYPE_VIDEO,
00298     .id             = CODEC_ID_NUV,
00299     .priv_data_size = sizeof(NuvContext),
00300     .init           = decode_init,
00301     .close          = decode_end,
00302     .decode         = decode_frame,
00303     .capabilities   = CODEC_CAP_DR1,
00304     .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"),
00305 };
00306