LCOV - code coverage report
Current view: top level - libavcodec - nuv.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 114 170 67.1 %
Date: 2017-12-13 10:57:33 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 result, init_frame = !avctx->frame_number;
     165             :     enum {
     166             :         NUV_UNCOMPRESSED  = '0',
     167             :         NUV_RTJPEG        = '1',
     168             :         NUV_RTJPEG_IN_LZO = '2',
     169             :         NUV_LZO           = '3',
     170             :         NUV_BLACK         = 'N',
     171             :         NUV_COPY_LAST     = 'L'
     172             :     } comptype;
     173             : 
     174          59 :     if (buf_size < 12) {
     175           0 :         av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
     176           0 :         return AVERROR_INVALIDDATA;
     177             :     }
     178             : 
     179             :     // codec data (rtjpeg quant tables)
     180          59 :     if (buf[0] == 'D' && buf[1] == 'R') {
     181             :         int ret;
     182             :         // Skip the rest of the frame header.
     183           0 :         buf       = &buf[12];
     184           0 :         buf_size -= 12;
     185           0 :         ret       = get_quant(avctx, c, buf, buf_size);
     186           0 :         if (ret < 0)
     187           0 :             return ret;
     188           0 :         ff_rtjpeg_decode_init(&c->rtj, c->width, c->height, c->lq, c->cq);
     189           0 :         return orig_size;
     190             :     }
     191             : 
     192          59 :     if (buf_size < 12 || buf[0] != 'V') {
     193           0 :         av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
     194           0 :         return AVERROR_INVALIDDATA;
     195             :     }
     196          59 :     comptype = buf[1];
     197          59 :     switch (comptype) {
     198          58 :     case NUV_RTJPEG_IN_LZO:
     199             :     case NUV_RTJPEG:
     200          58 :         keyframe = !buf[2];
     201          58 :         break;
     202           1 :     case NUV_COPY_LAST:
     203           1 :         keyframe = 0;
     204           1 :         break;
     205           0 :     default:
     206           0 :         keyframe = 1;
     207           0 :         break;
     208             :     }
     209          59 : retry:
     210             :     // Skip the rest of the frame header.
     211          59 :     buf       = &buf[12];
     212          59 :     buf_size -= 12;
     213          59 :     if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
     214          58 :         int outlen = c->decomp_size - FFMAX(AV_INPUT_BUFFER_PADDING_SIZE, AV_LZO_OUTPUT_PADDING);
     215          58 :         int inlen  = buf_size;
     216          58 :         if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) {
     217           1 :             av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
     218           1 :             return AVERROR_INVALIDDATA;
     219             :         }
     220          57 :         buf      = c->decomp_buf;
     221          57 :         buf_size = c->decomp_size - FFMAX(AV_INPUT_BUFFER_PADDING_SIZE, AV_LZO_OUTPUT_PADDING) - outlen;
     222          57 :         memset(c->decomp_buf + buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
     223             :     }
     224          58 :     if (c->codec_frameheader) {
     225             :         int w, h, q;
     226          50 :         if (buf_size < RTJPEG_HEADER_SIZE) {
     227           0 :             av_log(avctx, AV_LOG_ERROR, "Too small NUV video frame\n");
     228           0 :             return AVERROR_INVALIDDATA;
     229             :         }
     230             :         // There seem to exist two variants of this header: one starts with 'V'
     231             :         // and 5 bytes unknown, the other matches current MythTV and is 4 bytes size,
     232             :         // 1 byte header size (== 12), 1 byte version (== 0)
     233          50 :         if (buf[0] != 'V' && AV_RL16(&buf[4]) != 0x000c) {
     234           0 :             av_log(avctx, AV_LOG_ERROR, "Unknown secondary frame header (wrong codec_tag?)\n");
     235           0 :             return AVERROR_INVALIDDATA;
     236             :         }
     237          50 :         w = AV_RL16(&buf[6]);
     238          50 :         h = AV_RL16(&buf[8]);
     239          50 :         q = buf[10];
     240          50 :         if ((result = codec_reinit(avctx, w, h, q)) < 0)
     241           0 :             return result;
     242          50 :         if (result) {
     243           0 :             buf = avpkt->data;
     244           0 :             buf_size = avpkt->size;
     245           0 :             size_change = 1;
     246           0 :             goto retry;
     247             :         }
     248          50 :         buf       = &buf[RTJPEG_HEADER_SIZE];
     249          50 :         buf_size -= RTJPEG_HEADER_SIZE;
     250             :     }
     251             : 
     252          58 :     if (size_change || keyframe) {
     253           3 :         av_frame_unref(c->pic);
     254           3 :         init_frame = 1;
     255             :     }
     256             : 
     257          58 :     if ((result = ff_reget_buffer(avctx, c->pic)) < 0)
     258           0 :         return result;
     259          58 :     if (init_frame) {
     260           3 :         memset(c->pic->data[0], 0,    avctx->height * c->pic->linesize[0]);
     261           3 :         memset(c->pic->data[1], 0x80, avctx->height * c->pic->linesize[1] / 2);
     262           3 :         memset(c->pic->data[2], 0x80, avctx->height * c->pic->linesize[2] / 2);
     263             :     }
     264             : 
     265          58 :     c->pic->pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
     266          58 :     c->pic->key_frame = keyframe;
     267             :     // decompress/copy/whatever data
     268          58 :     switch (comptype) {
     269           0 :     case NUV_LZO:
     270             :     case NUV_UNCOMPRESSED: {
     271           0 :         int height = c->height;
     272           0 :         if (buf_size < c->width * height * 3 / 2) {
     273           0 :             av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
     274           0 :             height = buf_size / c->width / 3 * 2;
     275             :         }
     276           0 :         if(height > 0)
     277           0 :             copy_frame(c->pic, buf, c->width, height);
     278           0 :         break;
     279             :     }
     280          57 :     case NUV_RTJPEG_IN_LZO:
     281             :     case NUV_RTJPEG:
     282          57 :         ret = ff_rtjpeg_decode_frame_yuv420(&c->rtj, c->pic, buf, buf_size);
     283          57 :         if (ret < 0)
     284           0 :             return ret;
     285          57 :         break;
     286           0 :     case NUV_BLACK:
     287           0 :         memset(c->pic->data[0], 0, c->width * c->height);
     288           0 :         memset(c->pic->data[1], 128, c->width * c->height / 4);
     289           0 :         memset(c->pic->data[2], 128, c->width * c->height / 4);
     290           0 :         break;
     291           1 :     case NUV_COPY_LAST:
     292             :         /* nothing more to do here */
     293           1 :         break;
     294           0 :     default:
     295           0 :         av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
     296           0 :         return AVERROR_INVALIDDATA;
     297             :     }
     298             : 
     299          58 :     if ((result = av_frame_ref(picture, c->pic)) < 0)
     300           0 :         return result;
     301             : 
     302          58 :     *got_frame = 1;
     303          58 :     return orig_size;
     304             : }
     305             : 
     306           4 : static av_cold int decode_init(AVCodecContext *avctx)
     307             : {
     308           4 :     NuvContext *c  = avctx->priv_data;
     309             :     int ret;
     310             : 
     311           4 :     c->pic = av_frame_alloc();
     312           4 :     if (!c->pic)
     313           0 :         return AVERROR(ENOMEM);
     314             : 
     315           4 :     avctx->pix_fmt = AV_PIX_FMT_YUV420P;
     316           4 :     c->decomp_buf  = NULL;
     317           4 :     c->quality     = -1;
     318           4 :     c->width       = 0;
     319           4 :     c->height      = 0;
     320             : 
     321           4 :     c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G');
     322             : 
     323           4 :     if (avctx->extradata_size)
     324           4 :         get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
     325             : 
     326           4 :     ff_rtjpeg_init(&c->rtj, avctx);
     327             : 
     328           4 :     if ((ret = codec_reinit(avctx, avctx->width, avctx->height, -1)) < 0)
     329           0 :         return ret;
     330             : 
     331           4 :     return 0;
     332             : }
     333             : 
     334           4 : static av_cold int decode_end(AVCodecContext *avctx)
     335             : {
     336           4 :     NuvContext *c = avctx->priv_data;
     337             : 
     338           4 :     av_freep(&c->decomp_buf);
     339           4 :     av_frame_free(&c->pic);
     340             : 
     341           4 :     return 0;
     342             : }
     343             : 
     344             : AVCodec ff_nuv_decoder = {
     345             :     .name           = "nuv",
     346             :     .long_name      = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"),
     347             :     .type           = AVMEDIA_TYPE_VIDEO,
     348             :     .id             = AV_CODEC_ID_NUV,
     349             :     .priv_data_size = sizeof(NuvContext),
     350             :     .init           = decode_init,
     351             :     .close          = decode_end,
     352             :     .decode         = decode_frame,
     353             :     .capabilities   = AV_CODEC_CAP_DR1,
     354             : };

Generated by: LCOV version 1.13