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