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