annotate ffmpeg/libavcodec/nuv.c @ 13:844d341cf643 tip

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