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