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 "avcodec.h"
00025
00026 #include "bswap.h"
00027 #include "dsputil.h"
00028 #include "lzo.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 -1;
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 width = (width + 1) & ~1;
00111 height = (height + 1) & ~1;
00112 if (quality >= 0)
00113 get_quant_quality(c, quality);
00114 if (width != c->width || height != c->height) {
00115 if (avcodec_check_dimensions(avctx, height, width) < 0)
00116 return 0;
00117 avctx->width = c->width = width;
00118 avctx->height = c->height = height;
00119 c->decomp_size = c->height * c->width * 3 / 2;
00120 c->decomp_buf = av_realloc(c->decomp_buf, c->decomp_size + LZO_OUTPUT_PADDING);
00121 if (!c->decomp_buf) {
00122 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
00123 return 0;
00124 }
00125 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00126 } else if (quality != c->quality)
00127 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00128 return 1;
00129 }
00130
00131 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
00132 const uint8_t *buf, int buf_size) {
00133 NuvContext *c = avctx->priv_data;
00134 AVFrame *picture = data;
00135 int orig_size = buf_size;
00136 enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1',
00137 NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3',
00138 NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype;
00139
00140 if (buf_size < 12) {
00141 av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
00142 return -1;
00143 }
00144
00145
00146 if (buf[0] == 'D' && buf[1] == 'R') {
00147 int ret;
00148
00149 buf = &buf[12];
00150 buf_size -= 12;
00151 ret = get_quant(avctx, c, buf, buf_size);
00152 if (ret < 0)
00153 return ret;
00154 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00155 return orig_size;
00156 }
00157
00158 if (buf[0] != 'V' || buf_size < 12) {
00159 av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
00160 return -1;
00161 }
00162 comptype = buf[1];
00163
00164 buf = &buf[12];
00165 buf_size -= 12;
00166 if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
00167 int outlen = c->decomp_size, inlen = buf_size;
00168 if (lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
00169 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
00170 buf = c->decomp_buf;
00171 buf_size = c->decomp_size;
00172 }
00173 if (c->codec_frameheader) {
00174 int w, h, q;
00175 if (buf_size < 12) {
00176 av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n");
00177 return -1;
00178 }
00179 w = AV_RL16(&buf[6]);
00180 h = AV_RL16(&buf[8]);
00181 q = buf[10];
00182 if (!codec_reinit(avctx, w, h, q))
00183 return -1;
00184 buf = &buf[12];
00185 buf_size -= 12;
00186 }
00187
00188 if (c->pic.data[0])
00189 avctx->release_buffer(avctx, &c->pic);
00190 c->pic.reference = 1;
00191 c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE |
00192 FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00193 if (avctx->get_buffer(avctx, &c->pic) < 0) {
00194 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00195 return -1;
00196 }
00197
00198 c->pic.pict_type = FF_I_TYPE;
00199 c->pic.key_frame = 1;
00200
00201 switch (comptype) {
00202 case NUV_LZO:
00203 case NUV_UNCOMPRESSED: {
00204 int height = c->height;
00205 if (buf_size < c->width * height * 3 / 2) {
00206 av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
00207 height = buf_size / c->width / 3 * 2;
00208 }
00209 copy_frame(&c->pic, buf, c->width, height);
00210 break;
00211 }
00212 case NUV_RTJPEG_IN_LZO:
00213 case NUV_RTJPEG: {
00214 rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size);
00215 break;
00216 }
00217 case NUV_BLACK: {
00218 memset(c->pic.data[0], 0, c->width * c->height);
00219 memset(c->pic.data[1], 128, c->width * c->height / 4);
00220 memset(c->pic.data[2], 128, c->width * c->height / 4);
00221 break;
00222 }
00223 case NUV_COPY_LAST: {
00224 c->pic.pict_type = FF_P_TYPE;
00225 c->pic.key_frame = 0;
00226
00227 break;
00228 }
00229 default:
00230 av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
00231 return -1;
00232 }
00233
00234 *picture = c->pic;
00235 *data_size = sizeof(AVFrame);
00236 return orig_size;
00237 }
00238
00239 static int decode_init(AVCodecContext *avctx) {
00240 NuvContext *c = avctx->priv_data;
00241 avctx->pix_fmt = PIX_FMT_YUV420P;
00242 c->pic.data[0] = NULL;
00243 c->decomp_buf = NULL;
00244 c->quality = -1;
00245 c->width = 0;
00246 c->height = 0;
00247 c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G');
00248 if (avctx->extradata_size)
00249 get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
00250 dsputil_init(&c->dsp, avctx);
00251 if (!codec_reinit(avctx, avctx->width, avctx->height, -1))
00252 return 1;
00253 return 0;
00254 }
00255
00256 static int decode_end(AVCodecContext *avctx) {
00257 NuvContext *c = avctx->priv_data;
00258 av_freep(&c->decomp_buf);
00259 if (c->pic.data[0])
00260 avctx->release_buffer(avctx, &c->pic);
00261 return 0;
00262 }
00263
00264 AVCodec nuv_decoder = {
00265 "nuv",
00266 CODEC_TYPE_VIDEO,
00267 CODEC_ID_NUV,
00268 sizeof(NuvContext),
00269 decode_init,
00270 NULL,
00271 decode_end,
00272 decode_frame,
00273 CODEC_CAP_DR1,
00274 };
00275