00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "avcodec.h"
00024 #include "bytestream.h"
00025
00026 static av_cold int decode_init(AVCodecContext *avctx)
00027 {
00028 if (avctx->width & 1) {
00029 av_log(avctx, AV_LOG_ERROR, "frwu needs even width\n");
00030 return AVERROR(EINVAL);
00031 }
00032 avctx->pix_fmt = PIX_FMT_UYVY422;
00033
00034 avctx->coded_frame = avcodec_alloc_frame();
00035 if (!avctx->coded_frame)
00036 return AVERROR(ENOMEM);
00037
00038 return 0;
00039 }
00040
00041 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
00042 AVPacket *avpkt)
00043 {
00044 int field, ret;
00045 AVFrame *pic = avctx->coded_frame;
00046 const uint8_t *buf = avpkt->data;
00047 const uint8_t *buf_end = buf + avpkt->size;
00048
00049 if (pic->data[0])
00050 avctx->release_buffer(avctx, pic);
00051
00052 if (avpkt->size < avctx->width * 2 * avctx->height + 4 + 2*8) {
00053 av_log(avctx, AV_LOG_ERROR, "Packet is too small.\n");
00054 return AVERROR_INVALIDDATA;
00055 }
00056 if (bytestream_get_le32(&buf) != MKTAG('F', 'R', 'W', '1')) {
00057 av_log(avctx, AV_LOG_ERROR, "incorrect marker\n");
00058 return AVERROR_INVALIDDATA;
00059 }
00060
00061 pic->reference = 0;
00062 if ((ret = avctx->get_buffer(avctx, pic)) < 0) {
00063 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00064 return ret;
00065 }
00066
00067 pic->pict_type = AV_PICTURE_TYPE_I;
00068 pic->key_frame = 1;
00069 pic->interlaced_frame = 1;
00070 pic->top_field_first = 1;
00071
00072 for (field = 0; field < 2; field++) {
00073 int i;
00074 int field_h = (avctx->height + !field) >> 1;
00075 int field_size, min_field_size = avctx->width * 2 * field_h;
00076 uint8_t *dst = pic->data[0];
00077 if (buf_end - buf < 8)
00078 return AVERROR_INVALIDDATA;
00079 buf += 4;
00080 field_size = bytestream_get_le32(&buf);
00081 if (field_size < min_field_size) {
00082 av_log(avctx, AV_LOG_ERROR, "Field size %i is too small (required %i)\n", field_size, min_field_size);
00083 return AVERROR_INVALIDDATA;
00084 }
00085 if (buf_end - buf < field_size) {
00086 av_log(avctx, AV_LOG_ERROR, "Packet is too small, need %i, have %i\n", field_size, (int)(buf_end - buf));
00087 return AVERROR_INVALIDDATA;
00088 }
00089 if (field)
00090 dst += pic->linesize[0];
00091 for (i = 0; i < field_h; i++) {
00092 memcpy(dst, buf, avctx->width * 2);
00093 buf += avctx->width * 2;
00094 dst += pic->linesize[0] << 1;
00095 }
00096 buf += field_size - min_field_size;
00097 }
00098
00099 *data_size = sizeof(AVFrame);
00100 *(AVFrame*)data = *pic;
00101
00102 return avpkt->size;
00103 }
00104
00105 static av_cold int decode_close(AVCodecContext *avctx)
00106 {
00107 AVFrame *pic = avctx->coded_frame;
00108 if (pic->data[0])
00109 avctx->release_buffer(avctx, pic);
00110 av_freep(&avctx->coded_frame);
00111
00112 return 0;
00113 }
00114
00115 AVCodec ff_frwu_decoder = {
00116 .name = "frwu",
00117 .type = AVMEDIA_TYPE_VIDEO,
00118 .id = AV_CODEC_ID_FRWU,
00119 .init = decode_init,
00120 .close = decode_close,
00121 .decode = decode_frame,
00122 .capabilities = CODEC_CAP_DR1,
00123 .long_name = NULL_IF_CONFIG_SMALL("Forward Uncompressed"),
00124 };