4 * Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "bytestream.h"
26 #include "libavutil/opt.h"
30 int change_field_order
;
33 static av_cold
int decode_init(AVCodecContext
*avctx
)
35 if (avctx
->width
& 1) {
36 av_log(avctx
, AV_LOG_ERROR
, "frwu needs even width\n");
37 return AVERROR(EINVAL
);
39 avctx
->pix_fmt
= AV_PIX_FMT_UYVY422
;
44 static int decode_frame(AVCodecContext
*avctx
, void *data
, int *got_frame
,
47 FRWUContext
*s
= avctx
->priv_data
;
50 const uint8_t *buf
= avpkt
->data
;
51 const uint8_t *buf_end
= buf
+ avpkt
->size
;
53 if (avpkt
->size
< avctx
->width
* 2 * avctx
->height
+ 4 + 2*8) {
54 av_log(avctx
, AV_LOG_ERROR
, "Packet is too small.\n");
55 return AVERROR_INVALIDDATA
;
57 if (bytestream_get_le32(&buf
) != MKTAG('F', 'R', 'W', '1')) {
58 av_log(avctx
, AV_LOG_ERROR
, "incorrect marker\n");
59 return AVERROR_INVALIDDATA
;
62 if ((ret
= ff_get_buffer(avctx
, pic
, 0)) < 0)
65 pic
->pict_type
= AV_PICTURE_TYPE_I
;
68 for (field
= 0; field
< 2; field
++) {
70 int field_h
= (avctx
->height
+ !field
) >> 1;
71 int field_size
, min_field_size
= avctx
->width
* 2 * field_h
;
72 uint8_t *dst
= pic
->data
[0];
73 if (buf_end
- buf
< 8)
74 return AVERROR_INVALIDDATA
;
75 buf
+= 4; // flags? 0x80 == bottom field maybe?
76 field_size
= bytestream_get_le32(&buf
);
77 if (field_size
< min_field_size
) {
78 av_log(avctx
, AV_LOG_ERROR
, "Field size %i is too small (required %i)\n", field_size
, min_field_size
);
79 return AVERROR_INVALIDDATA
;
81 if (buf_end
- buf
< field_size
) {
82 av_log(avctx
, AV_LOG_ERROR
, "Packet is too small, need %i, have %i\n", field_size
, (int)(buf_end
- buf
));
83 return AVERROR_INVALIDDATA
;
85 if (field
^ s
->change_field_order
) {
86 dst
+= pic
->linesize
[0];
87 } else if (s
->change_field_order
) {
88 dst
+= 2 * pic
->linesize
[0];
90 for (i
= 0; i
< field_h
; i
++) {
91 if (s
->change_field_order
&& field
&& i
== field_h
- 1)
93 memcpy(dst
, buf
, avctx
->width
* 2);
94 buf
+= avctx
->width
* 2;
95 dst
+= pic
->linesize
[0] << 1;
97 buf
+= field_size
- min_field_size
;
105 static const AVOption frwu_options
[] = {
106 {"change_field_order", "Change field order", offsetof(FRWUContext
, change_field_order
), FF_OPT_TYPE_INT
,
107 {.i64
= 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM
| AV_OPT_FLAG_VIDEO_PARAM
},
111 static const AVClass frwu_class
= {
112 .class_name
= "frwu Decoder",
113 .item_name
= av_default_item_name
,
114 .option
= frwu_options
,
115 .version
= LIBAVUTIL_VERSION_INT
,
118 AVCodec ff_frwu_decoder
= {
120 .long_name
= NULL_IF_CONFIG_SMALL("Forward Uncompressed"),
121 .type
= AVMEDIA_TYPE_VIDEO
,
122 .id
= AV_CODEC_ID_FRWU
,
123 .priv_data_size
= sizeof(FRWUContext
),
125 .decode
= decode_frame
,
126 .capabilities
= CODEC_CAP_DR1
,
127 .priv_class
= &frwu_class
,