3 * Copyright (c) 2001, 2002, 2003 Fabrice Bellard
5 * This file is part of FFmpeg.
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.
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.
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
26 /* Header size increased to allow room for optional flags */
27 #define MAX_YUV4_HEADER 80
28 #define MAX_FRAME_HEADER 80
30 static int yuv4_read_header(AVFormatContext
*s
)
32 char header
[MAX_YUV4_HEADER
+ 10]; // Include headroom for
34 char *tokstart
, *tokend
, *header_end
;
36 AVIOContext
*pb
= s
->pb
;
37 int width
= -1, height
= -1, raten
= 0,
38 rated
= 0, aspectn
= 0, aspectd
= 0;
39 enum AVPixelFormat pix_fmt
= AV_PIX_FMT_NONE
, alt_pix_fmt
= AV_PIX_FMT_NONE
;
40 enum AVChromaLocation chroma_sample_location
= AVCHROMA_LOC_UNSPECIFIED
;
42 enum AVFieldOrder field_order
;
44 for (i
= 0; i
< MAX_YUV4_HEADER
; i
++) {
45 header
[i
] = avio_r8(pb
);
46 if (header
[i
] == '\n') {
47 header
[i
+ 1] = 0x20; // Add a space after last option.
48 // Makes parsing "444" vs "444alpha" easier.
53 if (i
== MAX_YUV4_HEADER
)
55 if (strncmp(header
, Y4M_MAGIC
, strlen(Y4M_MAGIC
)))
58 header_end
= &header
[i
+ 1]; // Include space
59 for (tokstart
= &header
[strlen(Y4M_MAGIC
) + 1];
60 tokstart
< header_end
; tokstart
++) {
61 if (*tokstart
== 0x20)
63 switch (*tokstart
++) {
64 case 'W': // Width. Required.
65 width
= strtol(tokstart
, &tokend
, 10);
68 case 'H': // Height. Required.
69 height
= strtol(tokstart
, &tokend
, 10);
72 case 'C': // Color space
73 if (strncmp("420jpeg", tokstart
, 7) == 0) {
74 pix_fmt
= AV_PIX_FMT_YUV420P
;
75 chroma_sample_location
= AVCHROMA_LOC_CENTER
;
76 } else if (strncmp("420mpeg2", tokstart
, 8) == 0) {
77 pix_fmt
= AV_PIX_FMT_YUV420P
;
78 chroma_sample_location
= AVCHROMA_LOC_LEFT
;
79 } else if (strncmp("420paldv", tokstart
, 8) == 0) {
80 pix_fmt
= AV_PIX_FMT_YUV420P
;
81 chroma_sample_location
= AVCHROMA_LOC_TOPLEFT
;
82 } else if (strncmp("420p16", tokstart
, 6) == 0) {
83 pix_fmt
= AV_PIX_FMT_YUV420P16
;
84 } else if (strncmp("422p16", tokstart
, 6) == 0) {
85 pix_fmt
= AV_PIX_FMT_YUV422P16
;
86 } else if (strncmp("444p16", tokstart
, 6) == 0) {
87 pix_fmt
= AV_PIX_FMT_YUV444P16
;
88 } else if (strncmp("420p14", tokstart
, 6) == 0) {
89 pix_fmt
= AV_PIX_FMT_YUV420P14
;
90 } else if (strncmp("422p14", tokstart
, 6) == 0) {
91 pix_fmt
= AV_PIX_FMT_YUV422P14
;
92 } else if (strncmp("444p14", tokstart
, 6) == 0) {
93 pix_fmt
= AV_PIX_FMT_YUV444P14
;
94 } else if (strncmp("420p12", tokstart
, 6) == 0) {
95 pix_fmt
= AV_PIX_FMT_YUV420P12
;
96 } else if (strncmp("422p12", tokstart
, 6) == 0) {
97 pix_fmt
= AV_PIX_FMT_YUV422P12
;
98 } else if (strncmp("444p12", tokstart
, 6) == 0) {
99 pix_fmt
= AV_PIX_FMT_YUV444P12
;
100 } else if (strncmp("420p10", tokstart
, 6) == 0) {
101 pix_fmt
= AV_PIX_FMT_YUV420P10
;
102 } else if (strncmp("422p10", tokstart
, 6) == 0) {
103 pix_fmt
= AV_PIX_FMT_YUV422P10
;
104 } else if (strncmp("444p10", tokstart
, 6) == 0) {
105 pix_fmt
= AV_PIX_FMT_YUV444P10
;
106 } else if (strncmp("420p9", tokstart
, 5) == 0) {
107 pix_fmt
= AV_PIX_FMT_YUV420P9
;
108 } else if (strncmp("422p9", tokstart
, 5) == 0) {
109 pix_fmt
= AV_PIX_FMT_YUV422P9
;
110 } else if (strncmp("444p9", tokstart
, 5) == 0) {
111 pix_fmt
= AV_PIX_FMT_YUV444P9
;
112 } else if (strncmp("420", tokstart
, 3) == 0) {
113 pix_fmt
= AV_PIX_FMT_YUV420P
;
114 chroma_sample_location
= AVCHROMA_LOC_CENTER
;
115 } else if (strncmp("411", tokstart
, 3) == 0) {
116 pix_fmt
= AV_PIX_FMT_YUV411P
;
117 } else if (strncmp("422", tokstart
, 3) == 0) {
118 pix_fmt
= AV_PIX_FMT_YUV422P
;
119 } else if (strncmp("444alpha", tokstart
, 8) == 0 ) {
120 av_log(s
, AV_LOG_ERROR
, "Cannot handle 4:4:4:4 "
121 "YUV4MPEG stream.\n");
123 } else if (strncmp("444", tokstart
, 3) == 0) {
124 pix_fmt
= AV_PIX_FMT_YUV444P
;
125 } else if (strncmp("mono16", tokstart
, 6) == 0) {
126 pix_fmt
= AV_PIX_FMT_GRAY16
;
127 } else if (strncmp("mono", tokstart
, 4) == 0) {
128 pix_fmt
= AV_PIX_FMT_GRAY8
;
130 av_log(s
, AV_LOG_ERROR
, "YUV4MPEG stream contains an unknown "
134 while (tokstart
< header_end
&& *tokstart
!= 0x20)
137 case 'I': // Interlace type
138 switch (*tokstart
++){
140 field_order
= AV_FIELD_UNKNOWN
;
143 field_order
= AV_FIELD_PROGRESSIVE
;
146 field_order
= AV_FIELD_TT
;
149 field_order
= AV_FIELD_BB
;
152 av_log(s
, AV_LOG_ERROR
, "YUV4MPEG stream contains mixed "
153 "interlaced and non-interlaced frames.\n");
155 av_log(s
, AV_LOG_ERROR
, "YUV4MPEG has invalid header.\n");
156 return AVERROR(EINVAL
);
159 case 'F': // Frame rate
160 sscanf(tokstart
, "%d:%d", &raten
, &rated
); // 0:0 if unknown
161 while (tokstart
< header_end
&& *tokstart
!= 0x20)
164 case 'A': // Pixel aspect
165 sscanf(tokstart
, "%d:%d", &aspectn
, &aspectd
); // 0:0 if unknown
166 while (tokstart
< header_end
&& *tokstart
!= 0x20)
169 case 'X': // Vendor extensions
170 if (strncmp("YSCSS=", tokstart
, 6) == 0) {
171 // Older nonstandard pixel format representation
173 if (strncmp("420JPEG", tokstart
, 7) == 0)
174 alt_pix_fmt
= AV_PIX_FMT_YUV420P
;
175 else if (strncmp("420MPEG2", tokstart
, 8) == 0)
176 alt_pix_fmt
= AV_PIX_FMT_YUV420P
;
177 else if (strncmp("420PALDV", tokstart
, 8) == 0)
178 alt_pix_fmt
= AV_PIX_FMT_YUV420P
;
179 else if (strncmp("420P9", tokstart
, 5) == 0)
180 alt_pix_fmt
= AV_PIX_FMT_YUV420P9
;
181 else if (strncmp("422P9", tokstart
, 5) == 0)
182 alt_pix_fmt
= AV_PIX_FMT_YUV422P9
;
183 else if (strncmp("444P9", tokstart
, 5) == 0)
184 alt_pix_fmt
= AV_PIX_FMT_YUV444P9
;
185 else if (strncmp("420P10", tokstart
, 6) == 0)
186 alt_pix_fmt
= AV_PIX_FMT_YUV420P10
;
187 else if (strncmp("422P10", tokstart
, 6) == 0)
188 alt_pix_fmt
= AV_PIX_FMT_YUV422P10
;
189 else if (strncmp("444P10", tokstart
, 6) == 0)
190 alt_pix_fmt
= AV_PIX_FMT_YUV444P10
;
191 else if (strncmp("420P12", tokstart
, 6) == 0)
192 alt_pix_fmt
= AV_PIX_FMT_YUV420P12
;
193 else if (strncmp("422P12", tokstart
, 6) == 0)
194 alt_pix_fmt
= AV_PIX_FMT_YUV422P12
;
195 else if (strncmp("444P12", tokstart
, 6) == 0)
196 alt_pix_fmt
= AV_PIX_FMT_YUV444P12
;
197 else if (strncmp("420P14", tokstart
, 6) == 0)
198 alt_pix_fmt
= AV_PIX_FMT_YUV420P14
;
199 else if (strncmp("422P14", tokstart
, 6) == 0)
200 alt_pix_fmt
= AV_PIX_FMT_YUV422P14
;
201 else if (strncmp("444P14", tokstart
, 6) == 0)
202 alt_pix_fmt
= AV_PIX_FMT_YUV444P14
;
203 else if (strncmp("420P16", tokstart
, 6) == 0)
204 alt_pix_fmt
= AV_PIX_FMT_YUV420P16
;
205 else if (strncmp("422P16", tokstart
, 6) == 0)
206 alt_pix_fmt
= AV_PIX_FMT_YUV422P16
;
207 else if (strncmp("444P16", tokstart
, 6) == 0)
208 alt_pix_fmt
= AV_PIX_FMT_YUV444P16
;
209 else if (strncmp("411", tokstart
, 3) == 0)
210 alt_pix_fmt
= AV_PIX_FMT_YUV411P
;
211 else if (strncmp("422", tokstart
, 3) == 0)
212 alt_pix_fmt
= AV_PIX_FMT_YUV422P
;
213 else if (strncmp("444", tokstart
, 3) == 0)
214 alt_pix_fmt
= AV_PIX_FMT_YUV444P
;
216 while (tokstart
< header_end
&& *tokstart
!= 0x20)
222 if (width
== -1 || height
== -1) {
223 av_log(s
, AV_LOG_ERROR
, "YUV4MPEG has invalid header.\n");
227 if (pix_fmt
== AV_PIX_FMT_NONE
) {
228 if (alt_pix_fmt
== AV_PIX_FMT_NONE
)
229 pix_fmt
= AV_PIX_FMT_YUV420P
;
231 pix_fmt
= alt_pix_fmt
;
234 if (raten
<= 0 || rated
<= 0) {
235 // Frame rate unknown
240 if (aspectn
== 0 && aspectd
== 0) {
241 // Pixel aspect unknown
245 st
= avformat_new_stream(s
, NULL
);
247 return AVERROR(ENOMEM
);
248 st
->codec
->width
= width
;
249 st
->codec
->height
= height
;
250 av_reduce(&raten
, &rated
, raten
, rated
, (1UL << 31) - 1);
251 avpriv_set_pts_info(st
, 64, rated
, raten
);
252 st
->avg_frame_rate
= av_inv_q(st
->time_base
);
253 st
->codec
->pix_fmt
= pix_fmt
;
254 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
255 st
->codec
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
256 st
->sample_aspect_ratio
= (AVRational
){ aspectn
, aspectd
};
257 st
->codec
->chroma_sample_location
= chroma_sample_location
;
258 st
->codec
->field_order
= field_order
;
263 static int yuv4_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
266 char header
[MAX_FRAME_HEADER
+1];
267 int packet_size
, width
, height
, ret
;
268 AVStream
*st
= s
->streams
[0];
270 for (i
= 0; i
< MAX_FRAME_HEADER
; i
++) {
271 header
[i
] = avio_r8(s
->pb
);
272 if (header
[i
] == '\n') {
279 else if (s
->pb
->eof_reached
)
281 else if (i
== MAX_FRAME_HEADER
)
282 return AVERROR_INVALIDDATA
;
284 if (strncmp(header
, Y4M_FRAME_MAGIC
, strlen(Y4M_FRAME_MAGIC
)))
285 return AVERROR_INVALIDDATA
;
287 width
= st
->codec
->width
;
288 height
= st
->codec
->height
;
290 packet_size
= avpicture_get_size(st
->codec
->pix_fmt
, width
, height
);
294 ret
= av_get_packet(s
->pb
, pkt
, packet_size
);
297 else if (ret
!= packet_size
)
298 return s
->pb
->eof_reached
? AVERROR_EOF
: AVERROR(EIO
);
300 pkt
->stream_index
= 0;
304 static int yuv4_probe(AVProbeData
*pd
)
306 /* check file header */
307 if (strncmp(pd
->buf
, Y4M_MAGIC
, sizeof(Y4M_MAGIC
) - 1) == 0)
308 return AVPROBE_SCORE_MAX
;
313 AVInputFormat ff_yuv4mpegpipe_demuxer
= {
314 .name
= "yuv4mpegpipe",
315 .long_name
= NULL_IF_CONFIG_SMALL("YUV4MPEG pipe"),
316 .read_probe
= yuv4_probe
,
317 .read_header
= yuv4_read_header
,
318 .read_packet
= yuv4_read_packet
,