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#include <stdio.h> 22#include <stdlib.h> 23 24#include "libavutil/bswap.h" 25#include "libavutil/lzo.h" 26#include "avcodec.h" 27#include "dsputil.h" 28#include "rtjpeg.h" 29 30typedef struct { 31 AVFrame pic; 32 int codec_frameheader; 33 int quality; 34 int width, height; 35 unsigned int decomp_size; 36 unsigned char* decomp_buf; 37 uint32_t lq[64], cq[64]; 38 RTJpegContext rtj; 39 DSPContext dsp; 40} NuvContext; 41 42static const uint8_t fallback_lquant[] = { 43 16, 11, 10, 16, 24, 40, 51, 61, 44 12, 12, 14, 19, 26, 58, 60, 55, 45 14, 13, 16, 24, 40, 57, 69, 56, 46 14, 17, 22, 29, 51, 87, 80, 62, 47 18, 22, 37, 56, 68, 109, 103, 77, 48 24, 35, 55, 64, 81, 104, 113, 92, 49 49, 64, 78, 87, 103, 121, 120, 101, 50 72, 92, 95, 98, 112, 100, 103, 99 51}; 52 53static const uint8_t fallback_cquant[] = { 54 17, 18, 24, 47, 99, 99, 99, 99, 55 18, 21, 26, 66, 99, 99, 99, 99, 56 24, 26, 56, 99, 99, 99, 99, 99, 57 47, 66, 99, 99, 99, 99, 99, 99, 58 99, 99, 99, 99, 99, 99, 99, 99, 59 99, 99, 99, 99, 99, 99, 99, 99, 60 99, 99, 99, 99, 99, 99, 99, 99, 61 99, 99, 99, 99, 99, 99, 99, 99 62}; 63 64/** 65 * \brief copy frame data from buffer to AVFrame, handling stride. 66 * \param f destination AVFrame 67 * \param src source buffer, does not use any line-stride 68 * \param width width of the video frame 69 * \param height height of the video frame 70 */ 71static void copy_frame(AVFrame *f, const uint8_t *src, 72 int width, int height) { 73 AVPicture pic; 74 avpicture_fill(&pic, src, PIX_FMT_YUV420P, width, height); 75 av_picture_copy((AVPicture *)f, &pic, PIX_FMT_YUV420P, width, height); 76} 77 78/** 79 * \brief extract quantization tables from codec data into our context 80 */ 81static int get_quant(AVCodecContext *avctx, NuvContext *c, 82 const uint8_t *buf, int size) { 83 int i; 84 if (size < 2 * 64 * 4) { 85 av_log(avctx, AV_LOG_ERROR, "insufficient rtjpeg quant data\n"); 86 return -1; 87 } 88 for (i = 0; i < 64; i++, buf += 4) 89 c->lq[i] = AV_RL32(buf); 90 for (i = 0; i < 64; i++, buf += 4) 91 c->cq[i] = AV_RL32(buf); 92 return 0; 93} 94 95/** 96 * \brief set quantization tables from a quality value 97 */ 98static void get_quant_quality(NuvContext *c, int quality) { 99 int i; 100 quality = FFMAX(quality, 1); 101 for (i = 0; i < 64; i++) { 102 c->lq[i] = (fallback_lquant[i] << 7) / quality; 103 c->cq[i] = (fallback_cquant[i] << 7) / quality; 104 } 105} 106 107static int codec_reinit(AVCodecContext *avctx, int width, int height, int quality) { 108 NuvContext *c = avctx->priv_data; 109 width = (width + 1) & ~1; 110 height = (height + 1) & ~1; 111 if (quality >= 0) 112 get_quant_quality(c, quality); 113 if (width != c->width || height != c->height) { 114 if (avcodec_check_dimensions(avctx, height, width) < 0) 115 return 0; 116 avctx->width = c->width = width; 117 avctx->height = c->height = height; 118 c->decomp_size = c->height * c->width * 3 / 2; 119 c->decomp_buf = av_realloc(c->decomp_buf, c->decomp_size + AV_LZO_OUTPUT_PADDING); 120 if (!c->decomp_buf) { 121 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); 122 return 0; 123 } 124 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq); 125 } else if (quality != c->quality) 126 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq); 127 return 1; 128} 129 130static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, 131 AVPacket *avpkt) { 132 const uint8_t *buf = avpkt->data; 133 int buf_size = avpkt->size; 134 NuvContext *c = avctx->priv_data; 135 AVFrame *picture = data; 136 int orig_size = buf_size; 137 int keyframe; 138 int result; 139 enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1', 140 NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3', 141 NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype; 142 143 if (buf_size < 12) { 144 av_log(avctx, AV_LOG_ERROR, "coded frame too small\n"); 145 return -1; 146 } 147 148 // codec data (rtjpeg quant tables) 149 if (buf[0] == 'D' && buf[1] == 'R') { 150 int ret; 151 // skip rest of the frameheader. 152 buf = &buf[12]; 153 buf_size -= 12; 154 ret = get_quant(avctx, c, buf, buf_size); 155 if (ret < 0) 156 return ret; 157 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq); 158 return orig_size; 159 } 160 161 if (buf[0] != 'V' || buf_size < 12) { 162 av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n"); 163 return -1; 164 } 165 comptype = buf[1]; 166 switch (comptype) { 167 case NUV_RTJPEG_IN_LZO: 168 case NUV_RTJPEG: 169 keyframe = !buf[2]; break; 170 case NUV_COPY_LAST: 171 keyframe = 0; break; 172 default: 173 keyframe = 1; break; 174 } 175 // skip rest of the frameheader. 176 buf = &buf[12]; 177 buf_size -= 12; 178 if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) { 179 int outlen = c->decomp_size, inlen = buf_size; 180 if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) 181 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); 182 buf = c->decomp_buf; 183 buf_size = c->decomp_size; 184 } 185 if (c->codec_frameheader) { 186 int w, h, q; 187 if (buf_size < 12) { 188 av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n"); 189 return -1; 190 } 191 w = AV_RL16(&buf[6]); 192 h = AV_RL16(&buf[8]); 193 q = buf[10]; 194 if (!codec_reinit(avctx, w, h, q)) 195 return -1; 196 buf = &buf[12]; 197 buf_size -= 12; 198 } 199 200 if (keyframe && c->pic.data[0]) 201 avctx->release_buffer(avctx, &c->pic); 202 c->pic.reference = 3; 203 c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE | 204 FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; 205 result = avctx->reget_buffer(avctx, &c->pic); 206 if (result < 0) { 207 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 208 return -1; 209 } 210 211 c->pic.pict_type = keyframe ? FF_I_TYPE : FF_P_TYPE; 212 c->pic.key_frame = keyframe; 213 // decompress/copy/whatever data 214 switch (comptype) { 215 case NUV_LZO: 216 case NUV_UNCOMPRESSED: { 217 int height = c->height; 218 if (buf_size < c->width * height * 3 / 2) { 219 av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n"); 220 height = buf_size / c->width / 3 * 2; 221 } 222 copy_frame(&c->pic, buf, c->width, height); 223 break; 224 } 225 case NUV_RTJPEG_IN_LZO: 226 case NUV_RTJPEG: { 227 rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size); 228 break; 229 } 230 case NUV_BLACK: { 231 memset(c->pic.data[0], 0, c->width * c->height); 232 memset(c->pic.data[1], 128, c->width * c->height / 4); 233 memset(c->pic.data[2], 128, c->width * c->height / 4); 234 break; 235 } 236 case NUV_COPY_LAST: { 237 /* nothing more to do here */ 238 break; 239 } 240 default: 241 av_log(avctx, AV_LOG_ERROR, "unknown compression\n"); 242 return -1; 243 } 244 245 *picture = c->pic; 246 *data_size = sizeof(AVFrame); 247 return orig_size; 248} 249 250static av_cold int decode_init(AVCodecContext *avctx) { 251 NuvContext *c = avctx->priv_data; 252 avctx->pix_fmt = PIX_FMT_YUV420P; 253 c->pic.data[0] = NULL; 254 c->decomp_buf = NULL; 255 c->quality = -1; 256 c->width = 0; 257 c->height = 0; 258 c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G'); 259 if (avctx->extradata_size) 260 get_quant(avctx, c, avctx->extradata, avctx->extradata_size); 261 dsputil_init(&c->dsp, avctx); 262 if (!codec_reinit(avctx, avctx->width, avctx->height, -1)) 263 return 1; 264 return 0; 265} 266 267static av_cold int decode_end(AVCodecContext *avctx) { 268 NuvContext *c = avctx->priv_data; 269 av_freep(&c->decomp_buf); 270 if (c->pic.data[0]) 271 avctx->release_buffer(avctx, &c->pic); 272 return 0; 273} 274 275AVCodec nuv_decoder = { 276 "nuv", 277 AVMEDIA_TYPE_VIDEO, 278 CODEC_ID_NUV, 279 sizeof(NuvContext), 280 decode_init, 281 NULL, 282 decode_end, 283 decode_frame, 284 CODEC_CAP_DR1, 285 .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"), 286}; 287 288