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