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