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

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 = (width + 1) & ~1;
00112     height = (height + 1) & ~1;
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;
00191     }
00192     if (c->codec_frameheader) {
00193         int w, h, q, res;
00194         if (buf_size < RTJPEG_HEADER_SIZE || buf[4] != RTJPEG_HEADER_SIZE ||
00195             buf[5] != RTJPEG_FILE_VERSION) {
00196             av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n");
00197             return AVERROR_INVALIDDATA;
00198         }
00199         w = AV_RL16(&buf[6]);
00200         h = AV_RL16(&buf[8]);
00201         q = buf[10];
00202         res = codec_reinit(avctx, w, h, q);
00203         if (res < 0)
00204             return res;
00205         if (res) {
00206             buf = avpkt->data;
00207             buf_size = avpkt->size;
00208             size_change = 1;
00209             goto retry;
00210         }
00211         buf = &buf[RTJPEG_HEADER_SIZE];
00212         buf_size -= RTJPEG_HEADER_SIZE;
00213     }
00214 
00215     if ((size_change || keyframe) && c->pic.data[0])
00216         avctx->release_buffer(avctx, &c->pic);
00217     c->pic.reference = 3;
00218     c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE |
00219                           FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00220     result = avctx->reget_buffer(avctx, &c->pic);
00221     if (result < 0) {
00222         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00223         return -1;
00224     }
00225 
00226     c->pic.pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
00227     c->pic.key_frame = keyframe;
00228     // decompress/copy/whatever data
00229     switch (comptype) {
00230         case NUV_LZO:
00231         case NUV_UNCOMPRESSED: {
00232             int height = c->height;
00233             if (buf_size < c->width * height * 3 / 2) {
00234                 av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
00235                 height = buf_size / c->width / 3 * 2;
00236             }
00237             copy_frame(&c->pic, buf, c->width, height);
00238             break;
00239         }
00240         case NUV_RTJPEG_IN_LZO:
00241         case NUV_RTJPEG: {
00242             rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size);
00243             break;
00244         }
00245         case NUV_BLACK: {
00246             memset(c->pic.data[0], 0, c->width * c->height);
00247             memset(c->pic.data[1], 128, c->width * c->height / 4);
00248             memset(c->pic.data[2], 128, c->width * c->height / 4);
00249             break;
00250         }
00251         case NUV_COPY_LAST: {
00252             /* nothing more to do here */
00253             break;
00254         }
00255         default:
00256             av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
00257             return -1;
00258     }
00259 
00260     *picture = c->pic;
00261     *data_size = sizeof(AVFrame);
00262     return orig_size;
00263 }
00264 
00265 static av_cold int decode_init(AVCodecContext *avctx) {
00266     NuvContext *c = avctx->priv_data;
00267     avctx->pix_fmt = PIX_FMT_YUV420P;
00268     c->pic.data[0] = NULL;
00269     c->decomp_buf = NULL;
00270     c->quality = -1;
00271     c->width = 0;
00272     c->height = 0;
00273     c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G');
00274     if (avctx->extradata_size)
00275         get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
00276     dsputil_init(&c->dsp, avctx);
00277     if (codec_reinit(avctx, avctx->width, avctx->height, -1) < 0)
00278         return 1;
00279     return 0;
00280 }
00281 
00282 static av_cold int decode_end(AVCodecContext *avctx) {
00283     NuvContext *c = avctx->priv_data;
00284     av_freep(&c->decomp_buf);
00285     if (c->pic.data[0])
00286         avctx->release_buffer(avctx, &c->pic);
00287     return 0;
00288 }
00289 
00290 AVCodec ff_nuv_decoder = {
00291     "nuv",
00292     AVMEDIA_TYPE_VIDEO,
00293     CODEC_ID_NUV,
00294     sizeof(NuvContext),
00295     decode_init,
00296     NULL,
00297     decode_end,
00298     decode_frame,
00299     CODEC_CAP_DR1,
00300     .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"),
00301 };
00302 

Generated on Fri Feb 22 2013 07:24:28 for FFmpeg by  doxygen 1.7.1