• 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                         const uint8_t *buf, int buf_size) {
00132     NuvContext *c = avctx->priv_data;
00133     AVFrame *picture = data;
00134     int orig_size = buf_size;
00135     int keyframe;
00136     int result;
00137     enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1',
00138           NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3',
00139           NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype;
00140 
00141     if (buf_size < 12) {
00142         av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
00143         return -1;
00144     }
00145 
00146     // codec data (rtjpeg quant tables)
00147     if (buf[0] == 'D' && buf[1] == 'R') {
00148         int ret;
00149         // skip rest of the frameheader.
00150         buf = &buf[12];
00151         buf_size -= 12;
00152         ret = get_quant(avctx, c, buf, buf_size);
00153         if (ret < 0)
00154             return ret;
00155         rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00156         return orig_size;
00157     }
00158 
00159     if (buf[0] != 'V' || buf_size < 12) {
00160         av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
00161         return -1;
00162     }
00163     comptype = buf[1];
00164     switch (comptype) {
00165         case NUV_RTJPEG_IN_LZO:
00166         case NUV_RTJPEG:
00167             keyframe = !buf[2]; break;
00168         case NUV_COPY_LAST:
00169             keyframe = 0; break;
00170         default:
00171             keyframe = 1; break;
00172     }
00173     // skip rest of the frameheader.
00174     buf = &buf[12];
00175     buf_size -= 12;
00176     if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
00177         int outlen = c->decomp_size, inlen = buf_size;
00178         if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
00179             av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
00180         buf = c->decomp_buf;
00181         buf_size = c->decomp_size;
00182     }
00183     if (c->codec_frameheader) {
00184         int w, h, q;
00185         if (buf_size < RTJPEG_HEADER_SIZE || buf[4] != RTJPEG_HEADER_SIZE ||
00186             buf[5] != RTJPEG_FILE_VERSION) {
00187             av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n");
00188             return AVERROR_INVALIDDATA;
00189         }
00190         w = AV_RL16(&buf[6]);
00191         h = AV_RL16(&buf[8]);
00192         q = buf[10];
00193         if (!codec_reinit(avctx, w, h, q))
00194             return -1;
00195         buf = &buf[RTJPEG_HEADER_SIZE];
00196         buf_size -= RTJPEG_HEADER_SIZE;
00197     }
00198 
00199     if (keyframe && c->pic.data[0])
00200         avctx->release_buffer(avctx, &c->pic);
00201     c->pic.reference = 1;
00202     c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE |
00203                           FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00204     result = keyframe ? avctx->get_buffer(avctx, &c->pic) : avctx->reget_buffer(avctx, &c->pic);
00205     if (result < 0) {
00206         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00207         return -1;
00208     }
00209 
00210     c->pic.pict_type = keyframe ? FF_I_TYPE : FF_P_TYPE;
00211     c->pic.key_frame = keyframe;
00212     // decompress/copy/whatever data
00213     switch (comptype) {
00214         case NUV_LZO:
00215         case NUV_UNCOMPRESSED: {
00216             int height = c->height;
00217             if (buf_size < c->width * height * 3 / 2) {
00218                 av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
00219                 height = buf_size / c->width / 3 * 2;
00220             }
00221             copy_frame(&c->pic, buf, c->width, height);
00222             break;
00223         }
00224         case NUV_RTJPEG_IN_LZO:
00225         case NUV_RTJPEG: {
00226             rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size);
00227             break;
00228         }
00229         case NUV_BLACK: {
00230             memset(c->pic.data[0], 0, c->width * c->height);
00231             memset(c->pic.data[1], 128, c->width * c->height / 4);
00232             memset(c->pic.data[2], 128, c->width * c->height / 4);
00233             break;
00234         }
00235         case NUV_COPY_LAST: {
00236             /* nothing more to do here */
00237             break;
00238         }
00239         default:
00240             av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
00241             return -1;
00242     }
00243 
00244     *picture = c->pic;
00245     *data_size = sizeof(AVFrame);
00246     return orig_size;
00247 }
00248 
00249 static av_cold int decode_init(AVCodecContext *avctx) {
00250     NuvContext *c = avctx->priv_data;
00251     avctx->pix_fmt = PIX_FMT_YUV420P;
00252     c->pic.data[0] = NULL;
00253     c->decomp_buf = NULL;
00254     c->quality = -1;
00255     c->width = 0;
00256     c->height = 0;
00257     c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G');
00258     if (avctx->extradata_size)
00259         get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
00260     dsputil_init(&c->dsp, avctx);
00261     if (!codec_reinit(avctx, avctx->width, avctx->height, -1))
00262         return 1;
00263     return 0;
00264 }
00265 
00266 static av_cold int decode_end(AVCodecContext *avctx) {
00267     NuvContext *c = avctx->priv_data;
00268     av_freep(&c->decomp_buf);
00269     if (c->pic.data[0])
00270         avctx->release_buffer(avctx, &c->pic);
00271     return 0;
00272 }
00273 
00274 AVCodec nuv_decoder = {
00275     "nuv",
00276     CODEC_TYPE_VIDEO,
00277     CODEC_ID_NUV,
00278     sizeof(NuvContext),
00279     decode_init,
00280     NULL,
00281     decode_end,
00282     decode_frame,
00283     CODEC_CAP_DR1,
00284     .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"),
00285 };
00286 

Generated on Sat Feb 16 2013 09:23:13 for ffmpeg by  doxygen 1.7.1