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 AVPacket *avpkt) {
00132 const uint8_t *buf = avpkt->data;
00133 int buf_size = avpkt->size;
00134 NuvContext *c = avctx->priv_data;
00135 AVFrame *picture = data;
00136 int orig_size = buf_size;
00137 int keyframe;
00138 int result;
00139 enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1',
00140 NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3',
00141 NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype;
00142
00143 if (buf_size < 12) {
00144 av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
00145 return -1;
00146 }
00147
00148
00149 if (buf[0] == 'D' && buf[1] == 'R') {
00150 int ret;
00151
00152 buf = &buf[12];
00153 buf_size -= 12;
00154 ret = get_quant(avctx, c, buf, buf_size);
00155 if (ret < 0)
00156 return ret;
00157 rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
00158 return orig_size;
00159 }
00160
00161 if (buf[0] != 'V' || buf_size < 12) {
00162 av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
00163 return -1;
00164 }
00165 comptype = buf[1];
00166 switch (comptype) {
00167 case NUV_RTJPEG_IN_LZO:
00168 case NUV_RTJPEG:
00169 keyframe = !buf[2]; break;
00170 case NUV_COPY_LAST:
00171 keyframe = 0; break;
00172 default:
00173 keyframe = 1; break;
00174 }
00175
00176 buf = &buf[12];
00177 buf_size -= 12;
00178 if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
00179 int outlen = c->decomp_size, inlen = buf_size;
00180 if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
00181 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
00182 buf = c->decomp_buf;
00183 buf_size = c->decomp_size;
00184 }
00185 if (c->codec_frameheader) {
00186 int w, h, q;
00187 if (buf_size < RTJPEG_HEADER_SIZE || buf[4] != RTJPEG_HEADER_SIZE ||
00188 buf[5] != RTJPEG_FILE_VERSION) {
00189 av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n");
00190 return AVERROR_INVALIDDATA;
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[RTJPEG_HEADER_SIZE];
00198 buf_size -= RTJPEG_HEADER_SIZE;
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