LCOV - code coverage report
Current view: top level - libavcodec - nuv.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 118 182 64.8 %
Date: 2018-05-20 11:54:08 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /*
       2             :  * NuppelVideo decoder
       3             :  * Copyright (c) 2006 Reimar Doeffinger
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Lesser General Public
       9             :  * License as published by the Free Software Foundation; either
      10             :  * version 2.1 of the License, or (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with FFmpeg; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <limits.h>
      25             : 
      26             : #include "libavutil/bswap.h"
      27             : #include "libavutil/common.h"
      28             : #include "libavutil/intreadwrite.h"
      29             : #include "libavutil/lzo.h"
      30             : #include "libavutil/imgutils.h"
      31             : #include "avcodec.h"
      32             : #include "idctdsp.h"
      33             : #include "internal.h"
      34             : #include "rtjpeg.h"
      35             : 
      36             : typedef struct NuvContext {
      37             :     AVFrame *pic;
      38             :     int codec_frameheader;
      39             :     int quality;
      40             :     int width, height;
      41             :     unsigned int decomp_size;
      42             :     unsigned char *decomp_buf;
      43             :     uint32_t lq[64], cq[64];
      44             :     RTJpegContext rtj;
      45             : } NuvContext;
      46             : 
      47             : static const uint8_t fallback_lquant[] = {
      48             :     16,  11,  10,  16,  24,  40,  51,  61,
      49             :     12,  12,  14,  19,  26,  58,  60,  55,
      50             :     14,  13,  16,  24,  40,  57,  69,  56,
      51             :     14,  17,  22,  29,  51,  87,  80,  62,
      52             :     18,  22,  37,  56,  68, 109, 103,  77,
      53             :     24,  35,  55,  64,  81, 104, 113,  92,
      54             :     49,  64,  78,  87, 103, 121, 120, 101,
      55             :     72,  92,  95,  98, 112, 100, 103,  99
      56             : };
      57             : 
      58             : static const uint8_t fallback_cquant[] = {
      59             :     17, 18, 24, 47, 99, 99, 99, 99,
      60             :     18, 21, 26, 66, 99, 99, 99, 99,
      61             :     24, 26, 56, 99, 99, 99, 99, 99,
      62             :     47, 66, 99, 99, 99, 99, 99, 99,
      63             :     99, 99, 99, 99, 99, 99, 99, 99,
      64             :     99, 99, 99, 99, 99, 99, 99, 99,
      65             :     99, 99, 99, 99, 99, 99, 99, 99,
      66             :     99, 99, 99, 99, 99, 99, 99, 99
      67             : };
      68             : 
      69             : /**
      70             :  * @brief copy frame data from buffer to AVFrame, handling stride.
      71             :  * @param f destination AVFrame
      72             :  * @param src source buffer, does not use any line-stride
      73             :  * @param width width of the video frame
      74             :  * @param height height of the video frame
      75             :  */
      76           0 : static void copy_frame(AVFrame *f, const uint8_t *src, int width, int height)
      77             : {
      78             :     uint8_t *src_data[4];
      79             :     int src_linesize[4];
      80           0 :     av_image_fill_arrays(src_data, src_linesize, src,
      81           0 :                          f->format, width, height, 1);
      82           0 :     av_image_copy(f->data, f->linesize, (const uint8_t **)src_data, src_linesize,
      83           0 :                   f->format, width, height);
      84           0 : }
      85             : 
      86             : /**
      87             :  * @brief extract quantization tables from codec data into our context
      88             :  */
      89           4 : static int get_quant(AVCodecContext *avctx, NuvContext *c, const uint8_t *buf,
      90             :                      int size)
      91             : {
      92             :     int i;
      93           4 :     if (size < 2 * 64 * 4) {
      94           0 :         av_log(avctx, AV_LOG_ERROR, "insufficient rtjpeg quant data\n");
      95           0 :         return AVERROR_INVALIDDATA;
      96             :     }
      97         260 :     for (i = 0; i < 64; i++, buf += 4)
      98         256 :         c->lq[i] = AV_RL32(buf);
      99         260 :     for (i = 0; i < 64; i++, buf += 4)
     100         256 :         c->cq[i] = AV_RL32(buf);
     101           4 :     return 0;
     102             : }
     103             : 
     104             : /**
     105             :  * @brief set quantization tables from a quality value
     106             :  */
     107          50 : static void get_quant_quality(NuvContext *c, int quality)
     108             : {
     109             :     int i;
     110          50 :     quality = FFMAX(quality, 1);
     111        3250 :     for (i = 0; i < 64; i++) {
     112        3200 :         c->lq[i] = (fallback_lquant[i] << 7) / quality;
     113        3200 :         c->cq[i] = (fallback_cquant[i] << 7) / quality;
     114             :     }
     115          50 : }
     116             : 
     117          54 : static int codec_reinit(AVCodecContext *avctx, int width, int height,
     118             :                         int quality)
     119             : {
     120          54 :     NuvContext *c = avctx->priv_data;
     121             :     int ret;
     122             : 
     123          54 :     width  = FFALIGN(width,  2);
     124          54 :     height = FFALIGN(height, 2);
     125          54 :     if (quality >= 0)
     126          50 :         get_quant_quality(c, quality);
     127          54 :     if (width != c->width || height != c->height) {
     128             :         // also reserve space for a possible additional header
     129           4 :         int buf_size = height * width * 3 / 2
     130             :                      + FFMAX(AV_LZO_OUTPUT_PADDING, AV_INPUT_BUFFER_PADDING_SIZE)
     131             :                      + RTJPEG_HEADER_SIZE;
     132           4 :         if (buf_size > INT_MAX/8)
     133           0 :             return -1;
     134           4 :         if ((ret = av_image_check_size(height, width, 0, avctx)) < 0)
     135           0 :             return ret;
     136           4 :         avctx->width  = c->width  = width;
     137           4 :         avctx->height = c->height = height;
     138           4 :         av_fast_malloc(&c->decomp_buf, &c->decomp_size,
     139             :                        buf_size);
     140           4 :         if (!c->decomp_buf) {
     141           0 :             av_log(avctx, AV_LOG_ERROR,
     142             :                    "Can't allocate decompression buffer.\n");
     143           0 :             return AVERROR(ENOMEM);
     144             :         }
     145           4 :         ff_rtjpeg_decode_init(&c->rtj, c->width, c->height, c->lq, c->cq);
     146           4 :         av_frame_unref(c->pic);
     147           4 :         return 1;
     148          50 :     } else if (quality != c->quality)
     149          50 :         ff_rtjpeg_decode_init(&c->rtj, c->width, c->height, c->lq, c->cq);
     150             : 
     151          50 :     return 0;
     152             : }
     153             : 
     154          59 : static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
     155             :                         AVPacket *avpkt)
     156             : {
     157          59 :     const uint8_t *buf = avpkt->data;
     158          59 :     int buf_size       = avpkt->size;
     159          59 :     NuvContext *c      = avctx->priv_data;
     160          59 :     AVFrame *picture   = data;
     161          59 :     int orig_size      = buf_size;
     162             :     int keyframe, ret;
     163          59 :     int size_change = 0;
     164          59 :     int minsize = 0;
     165          59 :     int result, init_frame = !avctx->frame_number;
     166             :     enum {
     167             :         NUV_UNCOMPRESSED  = '0',
     168             :         NUV_RTJPEG        = '1',
     169             :         NUV_RTJPEG_IN_LZO = '2',
     170             :         NUV_LZO           = '3',
     171             :         NUV_BLACK         = 'N',
     172             :         NUV_COPY_LAST     = 'L'
     173             :     } comptype;
     174             : 
     175          59 :     if (buf_size < 12) {
     176           0 :         av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
     177           0 :         return AVERROR_INVALIDDATA;
     178             :     }
     179             : 
     180             :     // codec data (rtjpeg quant tables)
     181          59 :     if (buf[0] == 'D' && buf[1] == 'R') {
     182             :         int ret;
     183             :         // Skip the rest of the frame header.
     184           0 :         buf       = &buf[12];
     185           0 :         buf_size -= 12;
     186           0 :         ret       = get_quant(avctx, c, buf, buf_size);
     187           0 :         if (ret < 0)
     188           0 :             return ret;
     189           0 :         ff_rtjpeg_decode_init(&c->rtj, c->width, c->height, c->lq, c->cq);
     190           0 :         return orig_size;
     191             :     }
     192             : 
     193          59 :     if (buf_size < 12 || buf[0] != 'V') {
     194           0 :         av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
     195           0 :         return AVERROR_INVALIDDATA;
     196             :     }
     197          59 :     comptype = buf[1];
     198          59 :     switch (comptype) {
     199          58 :     case NUV_RTJPEG_IN_LZO:
     200             :     case NUV_RTJPEG:
     201          58 :         keyframe = !buf[2];
     202          58 :         if (c->width < 16 || c->height < 16) {
     203           0 :             return AVERROR_INVALIDDATA;
     204             :         }
     205          58 :         break;
     206           1 :     case NUV_COPY_LAST:
     207           1 :         keyframe = 0;
     208           1 :         break;
     209           0 :     default:
     210           0 :         keyframe = 1;
     211           0 :         break;
     212             :     }
     213          59 :     switch (comptype) {
     214           0 :     case NUV_UNCOMPRESSED:
     215           0 :         minsize = c->width * c->height * 3 / 2;
     216           0 :         break;
     217           0 :     case NUV_RTJPEG:
     218           0 :         minsize = c->width/16 * (c->height/16) * 6;
     219           0 :         break;
     220             :     }
     221          59 :     if (buf_size < minsize / 4)
     222           0 :         return AVERROR_INVALIDDATA;
     223          59 : retry:
     224             :     // Skip the rest of the frame header.
     225          59 :     buf       = &buf[12];
     226          59 :     buf_size -= 12;
     227          59 :     if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
     228          58 :         int outlen = c->decomp_size - FFMAX(AV_INPUT_BUFFER_PADDING_SIZE, AV_LZO_OUTPUT_PADDING);
     229          58 :         int inlen  = buf_size;
     230          58 :         if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) {
     231           1 :             av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
     232           1 :             return AVERROR_INVALIDDATA;
     233             :         }
     234          57 :         buf      = c->decomp_buf;
     235          57 :         buf_size = c->decomp_size - FFMAX(AV_INPUT_BUFFER_PADDING_SIZE, AV_LZO_OUTPUT_PADDING) - outlen;
     236          57 :         memset(c->decomp_buf + buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
     237             :     }
     238          58 :     if (c->codec_frameheader) {
     239             :         int w, h, q;
     240          50 :         if (buf_size < RTJPEG_HEADER_SIZE) {
     241           0 :             av_log(avctx, AV_LOG_ERROR, "Too small NUV video frame\n");
     242           0 :             return AVERROR_INVALIDDATA;
     243             :         }
     244             :         // There seem to exist two variants of this header: one starts with 'V'
     245             :         // and 5 bytes unknown, the other matches current MythTV and is 4 bytes size,
     246             :         // 1 byte header size (== 12), 1 byte version (== 0)
     247          50 :         if (buf[0] != 'V' && AV_RL16(&buf[4]) != 0x000c) {
     248           0 :             av_log(avctx, AV_LOG_ERROR, "Unknown secondary frame header (wrong codec_tag?)\n");
     249           0 :             return AVERROR_INVALIDDATA;
     250             :         }
     251          50 :         w = AV_RL16(&buf[6]);
     252          50 :         h = AV_RL16(&buf[8]);
     253          50 :         q = buf[10];
     254          50 :         if ((result = codec_reinit(avctx, w, h, q)) < 0)
     255           0 :             return result;
     256          50 :         if (result) {
     257           0 :             buf = avpkt->data;
     258           0 :             buf_size = avpkt->size;
     259           0 :             size_change = 1;
     260           0 :             goto retry;
     261             :         }
     262          50 :         buf       = &buf[RTJPEG_HEADER_SIZE];
     263          50 :         buf_size -= RTJPEG_HEADER_SIZE;
     264             :     }
     265             : 
     266          58 :     if (size_change || keyframe) {
     267           3 :         av_frame_unref(c->pic);
     268           3 :         init_frame = 1;
     269             :     }
     270             : 
     271          58 :     if ((result = ff_reget_buffer(avctx, c->pic)) < 0)
     272           0 :         return result;
     273          58 :     if (init_frame) {
     274           3 :         memset(c->pic->data[0], 0,    avctx->height * c->pic->linesize[0]);
     275           3 :         memset(c->pic->data[1], 0x80, avctx->height * c->pic->linesize[1] / 2);
     276           3 :         memset(c->pic->data[2], 0x80, avctx->height * c->pic->linesize[2] / 2);
     277             :     }
     278             : 
     279          58 :     c->pic->pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
     280          58 :     c->pic->key_frame = keyframe;
     281             :     // decompress/copy/whatever data
     282          58 :     switch (comptype) {
     283           0 :     case NUV_LZO:
     284             :     case NUV_UNCOMPRESSED: {
     285           0 :         int height = c->height;
     286           0 :         if (buf_size < c->width * height * 3 / 2) {
     287           0 :             av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
     288           0 :             height = buf_size / c->width / 3 * 2;
     289             :         }
     290           0 :         if(height > 0)
     291           0 :             copy_frame(c->pic, buf, c->width, height);
     292           0 :         break;
     293             :     }
     294          57 :     case NUV_RTJPEG_IN_LZO:
     295             :     case NUV_RTJPEG:
     296          57 :         ret = ff_rtjpeg_decode_frame_yuv420(&c->rtj, c->pic, buf, buf_size);
     297          57 :         if (ret < 0)
     298           0 :             return ret;
     299          57 :         break;
     300           0 :     case NUV_BLACK:
     301           0 :         memset(c->pic->data[0], 0, c->width * c->height);
     302           0 :         memset(c->pic->data[1], 128, c->width * c->height / 4);
     303           0 :         memset(c->pic->data[2], 128, c->width * c->height / 4);
     304           0 :         break;
     305           1 :     case NUV_COPY_LAST:
     306             :         /* nothing more to do here */
     307           1 :         break;
     308           0 :     default:
     309           0 :         av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
     310           0 :         return AVERROR_INVALIDDATA;
     311             :     }
     312             : 
     313          58 :     if ((result = av_frame_ref(picture, c->pic)) < 0)
     314           0 :         return result;
     315             : 
     316          58 :     *got_frame = 1;
     317          58 :     return orig_size;
     318             : }
     319             : 
     320           4 : static av_cold int decode_init(AVCodecContext *avctx)
     321             : {
     322           4 :     NuvContext *c  = avctx->priv_data;
     323             :     int ret;
     324             : 
     325           4 :     c->pic = av_frame_alloc();
     326           4 :     if (!c->pic)
     327           0 :         return AVERROR(ENOMEM);
     328             : 
     329           4 :     avctx->pix_fmt = AV_PIX_FMT_YUV420P;
     330           4 :     c->decomp_buf  = NULL;
     331           4 :     c->quality     = -1;
     332           4 :     c->width       = 0;
     333           4 :     c->height      = 0;
     334             : 
     335           4 :     c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G');
     336             : 
     337           4 :     if (avctx->extradata_size)
     338           4 :         get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
     339             : 
     340           4 :     ff_rtjpeg_init(&c->rtj, avctx);
     341             : 
     342           4 :     if ((ret = codec_reinit(avctx, avctx->width, avctx->height, -1)) < 0)
     343           0 :         return ret;
     344             : 
     345           4 :     return 0;
     346             : }
     347             : 
     348           4 : static av_cold int decode_end(AVCodecContext *avctx)
     349             : {
     350           4 :     NuvContext *c = avctx->priv_data;
     351             : 
     352           4 :     av_freep(&c->decomp_buf);
     353           4 :     av_frame_free(&c->pic);
     354             : 
     355           4 :     return 0;
     356             : }
     357             : 
     358             : AVCodec ff_nuv_decoder = {
     359             :     .name           = "nuv",
     360             :     .long_name      = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"),
     361             :     .type           = AVMEDIA_TYPE_VIDEO,
     362             :     .id             = AV_CODEC_ID_NUV,
     363             :     .priv_data_size = sizeof(NuvContext),
     364             :     .init           = decode_init,
     365             :     .close          = decode_end,
     366             :     .decode         = decode_frame,
     367             :     .capabilities   = AV_CODEC_CAP_DR1,
     368             : };

Generated by: LCOV version 1.13