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 const uint8_t *buf, int buf_size) { 132 NuvContext *c = avctx->priv_data; 133 AVFrame *picture = data; 134 int orig_size = buf_size; 135 int keyframe; 136 int result; 137 enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1', 138 NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3', 139 NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype; 140 141 if (buf_size < 12) { 142 av_log(avctx, AV_LOG_ERROR, "coded frame too small\n"); 143 return -1; 144 } 145 146 // codec data (rtjpeg quant tables) 147 if (buf[0] == 'D' && buf[1] == 'R') { 148 int ret; 149 // skip rest of the frameheader. 150 buf = &buf[12]; 151 buf_size -= 12; 152 ret = get_quant(avctx, c, buf, buf_size); 153 if (ret < 0) 154 return ret; 155 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq); 156 return orig_size; 157 } 158 159 if (buf[0] != 'V' || buf_size < 12) { 160 av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n"); 161 return -1; 162 } 163 comptype = buf[1]; 164 switch (comptype) { 165 case NUV_RTJPEG_IN_LZO: 166 case NUV_RTJPEG: 167 keyframe = !buf[2]; break; 168 case NUV_COPY_LAST: 169 keyframe = 0; break; 170 default: 171 keyframe = 1; break; 172 } 173 // skip rest of the frameheader. 174 buf = &buf[12]; 175 buf_size -= 12; 176 if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) { 177 int outlen = c->decomp_size, inlen = buf_size; 178 if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) 179 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); 180 buf = c->decomp_buf; 181 buf_size = c->decomp_size; 182 } 183 if (c->codec_frameheader) { 184 int w, h, q; 185 if (buf_size < 12) { 186 av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n"); 187 return -1; 188 } 189 w = AV_RL16(&buf[6]); 190 h = AV_RL16(&buf[8]); 191 q = buf[10]; 192 if (!codec_reinit(avctx, w, h, q)) 193 return -1; 194 buf = &buf[12]; 195 buf_size -= 12; 196 } 197 198 if (keyframe && c->pic.data[0]) 199 avctx->release_buffer(avctx, &c->pic); 200 c->pic.reference = 1; 201 c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE | 202 FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; 203 result = keyframe ? avctx->get_buffer(avctx, &c->pic) : avctx->reget_buffer(avctx, &c->pic); 204 if (result < 0) { 205 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 206 return -1; 207 } 208 209 c->pic.pict_type = keyframe ? FF_I_TYPE : FF_P_TYPE; 210 c->pic.key_frame = keyframe; 211 // decompress/copy/whatever data 212 switch (comptype) { 213 case NUV_LZO: 214 case NUV_UNCOMPRESSED: { 215 int height = c->height; 216 if (buf_size < c->width * height * 3 / 2) { 217 av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n"); 218 height = buf_size / c->width / 3 * 2; 219 } 220 copy_frame(&c->pic, buf, c->width, height); 221 break; 222 } 223 case NUV_RTJPEG_IN_LZO: 224 case NUV_RTJPEG: { 225 rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size); 226 break; 227 } 228 case NUV_BLACK: { 229 memset(c->pic.data[0], 0, c->width * c->height); 230 memset(c->pic.data[1], 128, c->width * c->height / 4); 231 memset(c->pic.data[2], 128, c->width * c->height / 4); 232 break; 233 } 234 case NUV_COPY_LAST: { 235 /* nothing more to do here */ 236 break; 237 } 238 default: 239 av_log(avctx, AV_LOG_ERROR, "unknown compression\n"); 240 return -1; 241 } 242 243 *picture = c->pic; 244 *data_size = sizeof(AVFrame); 245 return orig_size; 246} 247 248static av_cold int decode_init(AVCodecContext *avctx) { 249 NuvContext *c = avctx->priv_data; 250 avctx->pix_fmt = PIX_FMT_YUV420P; 251 c->pic.data[0] = NULL; 252 c->decomp_buf = NULL; 253 c->quality = -1; 254 c->width = 0; 255 c->height = 0; 256 c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G'); 257 if (avctx->extradata_size) 258 get_quant(avctx, c, avctx->extradata, avctx->extradata_size); 259 dsputil_init(&c->dsp, avctx); 260 if (!codec_reinit(avctx, avctx->width, avctx->height, -1)) 261 return 1; 262 return 0; 263} 264 265static av_cold int decode_end(AVCodecContext *avctx) { 266 NuvContext *c = avctx->priv_data; 267 av_freep(&c->decomp_buf); 268 if (c->pic.data[0]) 269 avctx->release_buffer(avctx, &c->pic); 270 return 0; 271} 272 273AVCodec nuv_decoder = { 274 "nuv", 275 CODEC_TYPE_VIDEO, 276 CODEC_ID_NUV, 277 sizeof(NuvContext), 278 decode_init, 279 NULL, 280 decode_end, 281 decode_frame, 282 CODEC_CAP_DR1, 283 .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"), 284}; 285 286