00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023
00024 #include "libavutil/bswap.h"
00025 #include "libavutil/lzo.h"
00026 #include "libavutil/imgutils.h"
00027 #include "avcodec.h"
00028 #include "dsputil.h"
00029 #include "rtjpeg.h"
00030
00031 typedef struct {
00032 AVFrame pic;
00033 int codec_frameheader;
00034 int quality;
00035 int width, height;
00036 unsigned int decomp_size;
00037 unsigned char* decomp_buf;
00038 uint32_t lq[64], cq[64];
00039 RTJpegContext rtj;
00040 DSPContext dsp;
00041 } NuvContext;
00042
00043 static const uint8_t fallback_lquant[] = {
00044 16, 11, 10, 16, 24, 40, 51, 61,
00045 12, 12, 14, 19, 26, 58, 60, 55,
00046 14, 13, 16, 24, 40, 57, 69, 56,
00047 14, 17, 22, 29, 51, 87, 80, 62,
00048 18, 22, 37, 56, 68, 109, 103, 77,
00049 24, 35, 55, 64, 81, 104, 113, 92,
00050 49, 64, 78, 87, 103, 121, 120, 101,
00051 72, 92, 95, 98, 112, 100, 103, 99
00052 };
00053
00054 static const uint8_t fallback_cquant[] = {
00055 17, 18, 24, 47, 99, 99, 99, 99,
00056 18, 21, 26, 66, 99, 99, 99, 99,
00057 24, 26, 56, 99, 99, 99, 99, 99,
00058 47, 66, 99, 99, 99, 99, 99, 99,
00059 99, 99, 99, 99, 99, 99, 99, 99,
00060 99, 99, 99, 99, 99, 99, 99, 99,
00061 99, 99, 99, 99, 99, 99, 99, 99,
00062 99, 99, 99, 99, 99, 99, 99, 99
00063 };
00064
00072 static void copy_frame(AVFrame *f, const uint8_t *src,
00073 int width, int height) {
00074 AVPicture pic;
00075 avpicture_fill(&pic, src, PIX_FMT_YUV420P, width, height);
00076 av_picture_copy((AVPicture *)f, &pic, PIX_FMT_YUV420P, width, height);
00077 }
00078
00082 static int get_quant(AVCodecContext *avctx, NuvContext *c,
00083 const uint8_t *buf, int size) {
00084 int i;
00085 if (size < 2 * 64 * 4) {
00086 av_log(avctx, AV_LOG_ERROR, "insufficient rtjpeg quant data\n");
00087 return AVERROR_INVALIDDATA;
00088 }
00089 for (i = 0; i < 64; i++, buf += 4)
00090 c->lq[i] = AV_RL32(buf);
00091 for (i = 0; i < 64; i++, buf += 4)
00092 c->cq[i] = AV_RL32(buf);
00093 return 0;
00094 }
00095
00099 static void get_quant_quality(NuvContext *c, int quality) {
00100 int i;
00101 quality = FFMAX(quality, 1);
00102 for (i = 0; i < 64; i++) {
00103 c->lq[i] = (fallback_lquant[i] << 7) / quality;
00104 c->cq[i] = (fallback_cquant[i] << 7) / quality;
00105 }
00106 }
00107
00108 static int codec_reinit(AVCodecContext *avctx, int width, int height, int quality) {
00109 NuvContext *c = avctx->priv_data;
00110 int ret;
00111
00112 width = FFALIGN(width, 2);
00113 height = FFALIGN(height, 2);
00114 if (quality >= 0)
00115 get_quant_quality(c, quality);
00116 if (width != c->width || height != c->height) {
00117 void *ptr;
00118 if ((ret = av_image_check_size(height, width, 0, avctx)) < 0)
00119 return ret;
00120 avctx->width = c->width = width;
00121 avctx->height = c->height = height;
00122 ptr = av_fast_realloc(c->decomp_buf, &c->decomp_size,
00123 c->height * c->width * 3 / 2 +
00124 FF_INPUT_BUFFER_PADDING_SIZE +
00125 RTJPEG_HEADER_SIZE);
00126 if (!ptr) {
00127 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
00128 return AVERROR(ENOMEM);
00129 } else
00130 c->decomp_buf = ptr;
00131 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00132 if (c->pic.data[0])
00133 avctx->release_buffer(avctx, &c->pic);
00134 } else if (quality != c->quality)
00135 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00136 return 0;
00137 }
00138
00139 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
00140 AVPacket *avpkt) {
00141 const uint8_t *buf = avpkt->data;
00142 int buf_size = avpkt->size;
00143 NuvContext *c = avctx->priv_data;
00144 AVFrame *picture = data;
00145 int orig_size = buf_size;
00146 int keyframe;
00147 int result;
00148 int ret;
00149 enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1',
00150 NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3',
00151 NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype;
00152
00153 if (buf_size < 12) {
00154 av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
00155 return AVERROR_INVALIDDATA;
00156 }
00157
00158
00159 if (buf[0] == 'D' && buf[1] == 'R') {
00160 int ret;
00161
00162 buf = &buf[12];
00163 buf_size -= 12;
00164 ret = get_quant(avctx, c, buf, buf_size);
00165 if (ret < 0)
00166 return ret;
00167 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00168 return orig_size;
00169 }
00170
00171 if (buf[0] != 'V' || buf_size < 12) {
00172 av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
00173 return AVERROR_INVALIDDATA;
00174 }
00175 comptype = buf[1];
00176 switch (comptype) {
00177 case NUV_RTJPEG_IN_LZO:
00178 case NUV_RTJPEG:
00179 keyframe = !buf[2]; break;
00180 case NUV_COPY_LAST:
00181 keyframe = 0; break;
00182 default:
00183 keyframe = 1; break;
00184 }
00185
00186 buf = &buf[12];
00187 buf_size -= 12;
00188 if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
00189 int outlen = c->decomp_size - FF_INPUT_BUFFER_PADDING_SIZE;
00190 int inlen = buf_size;
00191 if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) {
00192 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
00193 return AVERROR_INVALIDDATA;
00194 }
00195 buf = c->decomp_buf;
00196 buf_size = outlen;
00197 }
00198 if (c->codec_frameheader) {
00199 int w, h, q;
00200 if (buf_size < RTJPEG_HEADER_SIZE || buf[4] != RTJPEG_HEADER_SIZE ||
00201 buf[5] != RTJPEG_FILE_VERSION) {
00202 av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n");
00203 return AVERROR_INVALIDDATA;
00204 }
00205 w = AV_RL16(&buf[6]);
00206 h = AV_RL16(&buf[8]);
00207 q = buf[10];
00208 if ((result = codec_reinit(avctx, w, h, q)) < 0)
00209 return result;
00210 if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO)
00211 buf = c->decomp_buf;
00212 buf = &buf[RTJPEG_HEADER_SIZE];
00213 buf_size -= RTJPEG_HEADER_SIZE;
00214 }
00215
00216 if (keyframe && c->pic.data[0])
00217 avctx->release_buffer(avctx, &c->pic);
00218 c->pic.reference = 3;
00219 c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE |
00220 FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00221 result = avctx->reget_buffer(avctx, &c->pic);
00222 if (result < 0) {
00223 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00224 return result;
00225 }
00226
00227 c->pic.pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
00228 c->pic.key_frame = keyframe;
00229
00230 switch (comptype) {
00231 case NUV_LZO:
00232 case NUV_UNCOMPRESSED: {
00233 int height = c->height;
00234 if (buf_size < c->width * height * 3 / 2) {
00235 av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
00236 height = buf_size / c->width / 3 * 2;
00237 }
00238 copy_frame(&c->pic, buf, c->width, height);
00239 break;
00240 }
00241 case NUV_RTJPEG_IN_LZO:
00242 case NUV_RTJPEG: {
00243 ret = rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size);
00244 if (ret < 0)
00245 return ret;
00246 break;
00247 }
00248 case NUV_BLACK: {
00249 memset(c->pic.data[0], 0, c->width * c->height);
00250 memset(c->pic.data[1], 128, c->width * c->height / 4);
00251 memset(c->pic.data[2], 128, c->width * c->height / 4);
00252 break;
00253 }
00254 case NUV_COPY_LAST: {
00255
00256 break;
00257 }
00258 default:
00259 av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
00260 return AVERROR_INVALIDDATA;
00261 }
00262
00263 *picture = c->pic;
00264 *data_size = sizeof(AVFrame);
00265 return orig_size;
00266 }
00267
00268 static av_cold int decode_init(AVCodecContext *avctx) {
00269 NuvContext *c = avctx->priv_data;
00270 int ret;
00271
00272 avctx->pix_fmt = PIX_FMT_YUV420P;
00273 c->pic.data[0] = NULL;
00274 c->decomp_buf = NULL;
00275 c->quality = -1;
00276 c->width = 0;
00277 c->height = 0;
00278 c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G');
00279 if (avctx->extradata_size)
00280 get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
00281 dsputil_init(&c->dsp, avctx);
00282 if ((ret = codec_reinit(avctx, avctx->width, avctx->height, -1)) < 0)
00283 return ret;
00284 return 0;
00285 }
00286
00287 static av_cold int decode_end(AVCodecContext *avctx) {
00288 NuvContext *c = avctx->priv_data;
00289 av_freep(&c->decomp_buf);
00290 if (c->pic.data[0])
00291 avctx->release_buffer(avctx, &c->pic);
00292 return 0;
00293 }
00294
00295 AVCodec ff_nuv_decoder = {
00296 .name = "nuv",
00297 .type = AVMEDIA_TYPE_VIDEO,
00298 .id = CODEC_ID_NUV,
00299 .priv_data_size = sizeof(NuvContext),
00300 .init = decode_init,
00301 .close = decode_end,
00302 .decode = decode_frame,
00303 .capabilities = CODEC_CAP_DR1,
00304 .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"),
00305 };
00306