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

Generated on Fri Sep 16 2011 17:17:41 for FFmpeg by  doxygen 1.7.1