/src/ffmpeg/libavformat/rawvideodec.c
Line | Count | Source |
1 | | /* |
2 | | * RAW video demuxer |
3 | | * Copyright (c) 2001 Fabrice Bellard |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * FFmpeg is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include "config_components.h" |
23 | | |
24 | | #include <stdbool.h> |
25 | | |
26 | | #include "libavutil/imgutils.h" |
27 | | #include "libavutil/parseutils.h" |
28 | | #include "libavutil/pixdesc.h" |
29 | | #include "libavutil/opt.h" |
30 | | #include "demux.h" |
31 | | #include "internal.h" |
32 | | #include "avformat.h" |
33 | | |
34 | | typedef struct RawVideoDemuxerContext { |
35 | | const AVClass *class; /**< Class for private options. */ |
36 | | int width, height; /**< Integers describing video size, set by a private option. */ |
37 | | enum AVPixelFormat pix_fmt; |
38 | | AVRational framerate; /**< AVRational describing framerate, set by a private option. */ |
39 | | |
40 | | bool has_padding; |
41 | | /* We could derive linesize[1 to N] from linesize[0] for multiplane formats, |
42 | | * but having users explicitly specify linesize for each plane can reduce |
43 | | * unexpected results and support more use cases. |
44 | | */ |
45 | | int *linesize; |
46 | | unsigned nb_linesize; |
47 | | // with padding |
48 | | size_t frame_size; |
49 | | // linesize without padding |
50 | | int raw_bytes[4]; |
51 | | } RawVideoDemuxerContext; |
52 | | |
53 | | // v210 frame width is padded to multiples of 48 |
54 | 0 | #define GET_PACKET_SIZE(w, h) (((w + 47) / 48) * 48 * h * 8 / 3) |
55 | | |
56 | | static int rawvideo_read_header(AVFormatContext *ctx) |
57 | 411 | { |
58 | 411 | RawVideoDemuxerContext *s = ctx->priv_data; |
59 | 411 | enum AVPixelFormat pix_fmt = s->pix_fmt; |
60 | 411 | AVStream *st; |
61 | 411 | int packet_size; |
62 | 411 | int ret; |
63 | | |
64 | 411 | st = avformat_new_stream(ctx, NULL); |
65 | 411 | if (!st) |
66 | 0 | return AVERROR(ENOMEM); |
67 | | |
68 | 411 | st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
69 | | |
70 | 411 | st->codecpar->codec_id = ffifmt(ctx->iformat)->raw_codec_id; |
71 | 411 | avpriv_set_pts_info(st, 64, s->framerate.den, s->framerate.num); |
72 | | |
73 | 411 | ret = av_image_check_size(s->width, s->height, 0, ctx); |
74 | 411 | if (ret < 0) |
75 | 411 | return ret; |
76 | | |
77 | 0 | st->codecpar->width = s->width; |
78 | 0 | st->codecpar->height = s->height; |
79 | |
|
80 | 0 | if (s->nb_linesize) { |
81 | 0 | int n = av_pix_fmt_count_planes(pix_fmt); |
82 | 0 | if (s->nb_linesize != n) { |
83 | 0 | av_log(ctx, AV_LOG_ERROR, "Invalid number of stride %u, " |
84 | 0 | "pixel format has %d plane\n", |
85 | 0 | s->nb_linesize, n); |
86 | 0 | return AVERROR(EINVAL); |
87 | 0 | } |
88 | | |
89 | 0 | ret = av_image_fill_linesizes(s->raw_bytes, pix_fmt, s->width); |
90 | 0 | if (ret < 0) |
91 | 0 | return ret; |
92 | | |
93 | 0 | size_t linesize[4] = {0}; |
94 | 0 | for (int i = 0; i < n; i++) { |
95 | 0 | if (s->linesize[i] < s->raw_bytes[i]) { |
96 | 0 | av_log(ctx, AV_LOG_ERROR, "Invalid stride %u of plane %d, " |
97 | 0 | "minimum required size is %d for width %d\n", |
98 | 0 | s->linesize[i], i, s->raw_bytes[i], s->width); |
99 | 0 | return AVERROR(EINVAL); |
100 | 0 | } |
101 | 0 | if (s->linesize[i] > s->raw_bytes[i]) |
102 | 0 | s->has_padding = true; |
103 | 0 | linesize[i] = s->linesize[i]; |
104 | 0 | } |
105 | | |
106 | 0 | size_t plane_size[4] = {0}; |
107 | 0 | av_image_fill_plane_sizes(plane_size, pix_fmt, s->height, linesize); |
108 | 0 | s->frame_size = plane_size[0] + plane_size[1] + plane_size[2] + plane_size[3]; |
109 | 0 | } |
110 | | |
111 | 0 | if (ffifmt(ctx->iformat)->raw_codec_id == AV_CODEC_ID_BITPACKED) { |
112 | 0 | unsigned int pgroup; /* size of the pixel group in bytes */ |
113 | 0 | unsigned int xinc; |
114 | 0 | const AVPixFmtDescriptor *desc; |
115 | 0 | int tag; |
116 | |
|
117 | 0 | desc = av_pix_fmt_desc_get(pix_fmt); |
118 | 0 | st->codecpar->bits_per_coded_sample = av_get_bits_per_pixel(desc); |
119 | 0 | if (pix_fmt == AV_PIX_FMT_YUV422P10) { |
120 | 0 | tag = MKTAG('U', 'Y', 'V', 'Y'); |
121 | 0 | pgroup = 5; |
122 | 0 | xinc = 2; |
123 | 0 | } else if (pix_fmt == AV_PIX_FMT_UYVY422) { |
124 | 0 | tag = MKTAG('U', 'Y', 'V', 'Y'); |
125 | 0 | pgroup = 4; |
126 | 0 | xinc = 2; |
127 | 0 | st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; |
128 | 0 | } else { |
129 | 0 | av_log(ctx, AV_LOG_ERROR, "unsupported format: %s for bitpacked.\n", |
130 | 0 | desc->name); |
131 | 0 | return AVERROR(EINVAL); |
132 | 0 | } |
133 | 0 | st->codecpar->codec_tag = tag; |
134 | 0 | packet_size = s->width * s->height * pgroup / xinc; |
135 | 0 | } else if ((ffifmt(ctx->iformat)->raw_codec_id == AV_CODEC_ID_V210) || |
136 | 0 | (ffifmt(ctx->iformat)->raw_codec_id == AV_CODEC_ID_V210X)) { |
137 | 0 | pix_fmt = ffifmt(ctx->iformat)->raw_codec_id == AV_CODEC_ID_V210 ? |
138 | 0 | AV_PIX_FMT_YUV422P10 : AV_PIX_FMT_YUV422P16; |
139 | |
|
140 | 0 | packet_size = GET_PACKET_SIZE(s->width, s->height); |
141 | 0 | } else { |
142 | 0 | packet_size = av_image_get_buffer_size(pix_fmt, s->width, s->height, 1); |
143 | 0 | if (packet_size < 0) |
144 | 0 | return packet_size; |
145 | 0 | } |
146 | 0 | if (packet_size == 0) |
147 | 0 | return AVERROR(EINVAL); |
148 | | |
149 | 0 | st->codecpar->format = pix_fmt; |
150 | 0 | ctx->packet_size = packet_size; |
151 | 0 | st->codecpar->bit_rate = av_rescale_q(ctx->packet_size, |
152 | 0 | (AVRational){8,1}, st->time_base); |
153 | |
|
154 | 0 | return 0; |
155 | 0 | } |
156 | | |
157 | | |
158 | | static int rawvideo_read_packet(AVFormatContext *ctx, AVPacket *pkt) |
159 | 0 | { |
160 | 0 | int ret; |
161 | 0 | RawVideoDemuxerContext *s = ctx->priv_data; |
162 | |
|
163 | 0 | if (!s->has_padding) { |
164 | 0 | ret = av_get_packet(ctx->pb, pkt, ctx->packet_size); |
165 | 0 | if (ret < 0) |
166 | 0 | return ret; |
167 | 0 | pkt->pts = pkt->dts = pkt->pos / ctx->packet_size; |
168 | |
|
169 | 0 | return 0; |
170 | 0 | } |
171 | | |
172 | 0 | ret = av_new_packet(pkt, ctx->packet_size); |
173 | 0 | if (ret < 0) |
174 | 0 | return ret; |
175 | | |
176 | 0 | pkt->pos = avio_tell(ctx->pb); |
177 | 0 | pkt->pts = pkt->dts = pkt->pos / s->frame_size; |
178 | |
|
179 | 0 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->pix_fmt); |
180 | 0 | uint8_t *p = pkt->data; |
181 | 0 | for (int i = 0; i < s->nb_linesize; i++) { |
182 | 0 | int shift = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; |
183 | 0 | int h = AV_CEIL_RSHIFT(s->height, shift); |
184 | 0 | int skip_bytes = s->linesize[i] - s->raw_bytes[i]; |
185 | |
|
186 | 0 | for (int j = 0; j < h; j++) { |
187 | 0 | ret = avio_read(ctx->pb, p, s->raw_bytes[i]); |
188 | 0 | if (ret != s->raw_bytes[i]) { |
189 | 0 | if (ret < 0 && ret != AVERROR_EOF) |
190 | 0 | return ret; |
191 | | |
192 | 0 | if (ret == AVERROR_EOF && p == pkt->data) |
193 | 0 | return AVERROR_EOF; |
194 | | |
195 | 0 | memset(p, 0, pkt->size - (p - pkt->data)); |
196 | 0 | pkt->flags |= AV_PKT_FLAG_CORRUPT; |
197 | |
|
198 | 0 | return 0; |
199 | 0 | } |
200 | | |
201 | 0 | p += s->raw_bytes[i]; |
202 | 0 | avio_skip(ctx->pb, skip_bytes); |
203 | 0 | } |
204 | 0 | } |
205 | | |
206 | 0 | return 0; |
207 | 0 | } |
208 | | |
209 | | #define OFFSET(x) offsetof(RawVideoDemuxerContext, x) |
210 | | #define DEC AV_OPT_FLAG_DECODING_PARAM |
211 | | static const AVOption rawvideo_options[] = { |
212 | | // Only supported by rawvideo demuxer |
213 | | {"stride", "frame line size in bytes", OFFSET(linesize), AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, {.arr = NULL}, 0, INT_MAX, DEC }, |
214 | | #define BITPACKED_OPTION_OFFSET 1 // skip stride option |
215 | | /* pixel_format is not used by the v210 demuxers. */ |
216 | | { "pixel_format", "set pixel format", OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV420P}, AV_PIX_FMT_YUV420P, INT_MAX, DEC }, |
217 | | #define V210_OPTION_OFFSET 2 // skip stride and pixel_format option |
218 | | { "video_size", "set frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC }, |
219 | | { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC }, |
220 | | { NULL }, |
221 | | }; |
222 | | |
223 | | static const AVClass rawvideo_demuxer_class = { |
224 | | .class_name = "rawvideo demuxer", |
225 | | .item_name = av_default_item_name, |
226 | | .option = rawvideo_options, |
227 | | .version = LIBAVUTIL_VERSION_INT, |
228 | | }; |
229 | | |
230 | | const FFInputFormat ff_rawvideo_demuxer = { |
231 | | .p.name = "rawvideo", |
232 | | .p.long_name = NULL_IF_CONFIG_SMALL("raw video"), |
233 | | .p.flags = AVFMT_GENERIC_INDEX, |
234 | | .p.extensions = "yuv,cif,qcif,rgb", |
235 | | .p.priv_class = &rawvideo_demuxer_class, |
236 | | .priv_data_size = sizeof(RawVideoDemuxerContext), |
237 | | .read_header = rawvideo_read_header, |
238 | | .read_packet = rawvideo_read_packet, |
239 | | .raw_codec_id = AV_CODEC_ID_RAWVIDEO, |
240 | | }; |
241 | | |
242 | | static const AVClass bitpacked_demuxer_class = { |
243 | | .class_name = "bitpacked demuxer", |
244 | | .item_name = av_default_item_name, |
245 | | .option = &rawvideo_options[BITPACKED_OPTION_OFFSET], |
246 | | .version = LIBAVUTIL_VERSION_INT, |
247 | | }; |
248 | | |
249 | | #if CONFIG_BITPACKED_DEMUXER |
250 | | const FFInputFormat ff_bitpacked_demuxer = { |
251 | | .p.name = "bitpacked", |
252 | | .p.long_name = NULL_IF_CONFIG_SMALL("Bitpacked"), |
253 | | .p.flags = AVFMT_GENERIC_INDEX, |
254 | | .p.extensions = "bitpacked", |
255 | | .p.priv_class = &bitpacked_demuxer_class, |
256 | | .priv_data_size = sizeof(RawVideoDemuxerContext), |
257 | | .read_header = rawvideo_read_header, |
258 | | .read_packet = rawvideo_read_packet, |
259 | | .raw_codec_id = AV_CODEC_ID_BITPACKED, |
260 | | }; |
261 | | #endif // CONFIG_BITPACKED_DEMUXER |
262 | | |
263 | | static const AVClass v210_demuxer_class = { |
264 | | .class_name = "v210(x) demuxer", |
265 | | .item_name = av_default_item_name, |
266 | | .option = &rawvideo_options[V210_OPTION_OFFSET], |
267 | | .version = LIBAVUTIL_VERSION_INT, |
268 | | }; |
269 | | |
270 | | #if CONFIG_V210_DEMUXER |
271 | | const FFInputFormat ff_v210_demuxer = { |
272 | | .p.name = "v210", |
273 | | .p.long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), |
274 | | .p.flags = AVFMT_GENERIC_INDEX, |
275 | | .p.extensions = "v210", |
276 | | .p.priv_class = &v210_demuxer_class, |
277 | | .priv_data_size = sizeof(RawVideoDemuxerContext), |
278 | | .read_header = rawvideo_read_header, |
279 | | .read_packet = rawvideo_read_packet, |
280 | | .raw_codec_id = AV_CODEC_ID_V210, |
281 | | }; |
282 | | #endif // CONFIG_V210_DEMUXER |
283 | | |
284 | | #if CONFIG_V210X_DEMUXER |
285 | | const FFInputFormat ff_v210x_demuxer = { |
286 | | .p.name = "v210x", |
287 | | .p.long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), |
288 | | .p.flags = AVFMT_GENERIC_INDEX, |
289 | | .p.extensions = "yuv10", |
290 | | .p.priv_class = &v210_demuxer_class, |
291 | | .priv_data_size = sizeof(RawVideoDemuxerContext), |
292 | | .read_header = rawvideo_read_header, |
293 | | .read_packet = rawvideo_read_packet, |
294 | | .raw_codec_id = AV_CODEC_ID_V210X, |
295 | | }; |
296 | | #endif // CONFIG_V210X_DEMUXER |