• 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 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 -1;
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     width  = FFALIGN(width,  2);
00111     height = FFALIGN(height, 2);
00112     if (quality >= 0)
00113         get_quant_quality(c, quality);
00114     if (width != c->width || height != c->height) {
00115         if (av_image_check_size(height, width, 0, avctx) < 0)
00116             return 0;
00117         avctx->width = c->width = width;
00118         avctx->height = c->height = height;
00119         av_fast_malloc(&c->decomp_buf, &c->decomp_size, c->height * c->width * 3 / 2);
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[0] != 'V' || buf_size < 12) {
00188             av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame (wrong codec_tag?)\n");
00189             return AVERROR_INVALIDDATA;
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 ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
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 ff_nuv_decoder = {
00276     .name           = "nuv",
00277     .type           = AVMEDIA_TYPE_VIDEO,
00278     .id             = CODEC_ID_NUV,
00279     .priv_data_size = sizeof(NuvContext),
00280     .init           = decode_init,
00281     .close          = decode_end,
00282     .decode         = decode_frame,
00283     .capabilities   = CODEC_CAP_DR1,
00284     .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"),
00285 };
00286 
Generated on Sat Mar 17 2012 12:57:48 for Libav by doxygen 1.7.1