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 "libavcore/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 -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 (av_image_check_size(height, width, 0, avctx) < 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 + AV_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 AVPacket *avpkt) {
00133 const uint8_t *buf = avpkt->data;
00134 int buf_size = avpkt->size;
00135 NuvContext *c = avctx->priv_data;
00136 AVFrame *picture = data;
00137 int orig_size = buf_size;
00138 int keyframe;
00139 int result;
00140 enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1',
00141 NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3',
00142 NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype;
00143
00144 if (buf_size < 12) {
00145 av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
00146 return -1;
00147 }
00148
00149
00150 if (buf[0] == 'D' && buf[1] == 'R') {
00151 int ret;
00152
00153 buf = &buf[12];
00154 buf_size -= 12;
00155 ret = get_quant(avctx, c, buf, buf_size);
00156 if (ret < 0)
00157 return ret;
00158 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00159 return orig_size;
00160 }
00161
00162 if (buf[0] != 'V' || buf_size < 12) {
00163 av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
00164 return -1;
00165 }
00166 comptype = buf[1];
00167 switch (comptype) {
00168 case NUV_RTJPEG_IN_LZO:
00169 case NUV_RTJPEG:
00170 keyframe = !buf[2]; break;
00171 case NUV_COPY_LAST:
00172 keyframe = 0; break;
00173 default:
00174 keyframe = 1; break;
00175 }
00176
00177 buf = &buf[12];
00178 buf_size -= 12;
00179 if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
00180 int outlen = c->decomp_size, inlen = buf_size;
00181 if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
00182 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
00183 buf = c->decomp_buf;
00184 buf_size = c->decomp_size;
00185 }
00186 if (c->codec_frameheader) {
00187 int w, h, q;
00188 if (buf_size < 12) {
00189 av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n");
00190 return -1;
00191 }
00192 w = AV_RL16(&buf[6]);
00193 h = AV_RL16(&buf[8]);
00194 q = buf[10];
00195 if (!codec_reinit(avctx, w, h, q))
00196 return -1;
00197 buf = &buf[12];
00198 buf_size -= 12;
00199 }
00200
00201 if (keyframe && c->pic.data[0])
00202 avctx->release_buffer(avctx, &c->pic);
00203 c->pic.reference = 3;
00204 c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE |
00205 FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00206 result = avctx->reget_buffer(avctx, &c->pic);
00207 if (result < 0) {
00208 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00209 return -1;
00210 }
00211
00212 c->pic.pict_type = keyframe ? FF_I_TYPE : FF_P_TYPE;
00213 c->pic.key_frame = keyframe;
00214
00215 switch (comptype) {
00216 case NUV_LZO:
00217 case NUV_UNCOMPRESSED: {
00218 int height = c->height;
00219 if (buf_size < c->width * height * 3 / 2) {
00220 av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
00221 height = buf_size / c->width / 3 * 2;
00222 }
00223 copy_frame(&c->pic, buf, c->width, height);
00224 break;
00225 }
00226 case NUV_RTJPEG_IN_LZO:
00227 case NUV_RTJPEG: {
00228 rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size);
00229 break;
00230 }
00231 case NUV_BLACK: {
00232 memset(c->pic.data[0], 0, c->width * c->height);
00233 memset(c->pic.data[1], 128, c->width * c->height / 4);
00234 memset(c->pic.data[2], 128, c->width * c->height / 4);
00235 break;
00236 }
00237 case NUV_COPY_LAST: {
00238
00239 break;
00240 }
00241 default:
00242 av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
00243 return -1;
00244 }
00245
00246 *picture = c->pic;
00247 *data_size = sizeof(AVFrame);
00248 return orig_size;
00249 }
00250
00251 static av_cold int decode_init(AVCodecContext *avctx) {
00252 NuvContext *c = avctx->priv_data;
00253 avctx->pix_fmt = PIX_FMT_YUV420P;
00254 c->pic.data[0] = NULL;
00255 c->decomp_buf = NULL;
00256 c->quality = -1;
00257 c->width = 0;
00258 c->height = 0;
00259 c->codec_frameheader = avctx->codec_tag == MKTAG('R', 'J', 'P', 'G');
00260 if (avctx->extradata_size)
00261 get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
00262 dsputil_init(&c->dsp, avctx);
00263 if (!codec_reinit(avctx, avctx->width, avctx->height, -1))
00264 return 1;
00265 return 0;
00266 }
00267
00268 static av_cold int decode_end(AVCodecContext *avctx) {
00269 NuvContext *c = avctx->priv_data;
00270 av_freep(&c->decomp_buf);
00271 if (c->pic.data[0])
00272 avctx->release_buffer(avctx, &c->pic);
00273 return 0;
00274 }
00275
00276 AVCodec nuv_decoder = {
00277 "nuv",
00278 AVMEDIA_TYPE_VIDEO,
00279 CODEC_ID_NUV,
00280 sizeof(NuvContext),
00281 decode_init,
00282 NULL,
00283 decode_end,
00284 decode_frame,
00285 CODEC_CAP_DR1,
00286 .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"),
00287 };
00288