1 /*
2 * YUV4MPEG muxer
3 * Copyright (c) 2001, 2002, 2003 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 "libavutil/pixdesc.h"
23 #include "avformat.h"
24 #include "internal.h"
25 #include "yuv4mpeg.h"
26
yuv4_write_header(AVFormatContext * s)27 static int yuv4_write_header(AVFormatContext *s)
28 {
29 AVStream *st;
30 AVIOContext *pb = s->pb;
31 int width, height;
32 int raten, rated, aspectn, aspectd, ret;
33 char inter;
34 const char *colorspace = "";
35 const char *colorrange = "";
36 int field_order;
37
38 st = s->streams[0];
39 width = st->codecpar->width;
40 height = st->codecpar->height;
41 field_order = st->codecpar->field_order;
42
43 // TODO: should be avg_frame_rate
44 av_reduce(&raten, &rated, st->time_base.den,
45 st->time_base.num, (1UL << 31) - 1);
46
47 aspectn = st->sample_aspect_ratio.num;
48 aspectd = st->sample_aspect_ratio.den;
49
50 if (aspectn == 0 && aspectd == 1)
51 aspectd = 0; // 0:0 means unknown
52
53 #if FF_API_LAVF_AVCTX
54 FF_DISABLE_DEPRECATION_WARNINGS
55 if (field_order != st->codec->field_order && st->codec->field_order != AV_FIELD_UNKNOWN)
56 field_order = st->codec->field_order;
57 FF_ENABLE_DEPRECATION_WARNINGS
58 #endif
59
60 switch(st->codecpar->color_range) {
61 case AVCOL_RANGE_MPEG:
62 colorrange = " XCOLORRANGE=LIMITED";
63 break;
64 case AVCOL_RANGE_JPEG:
65 colorrange = " XCOLORRANGE=FULL";
66 break;
67 default:
68 break;
69 }
70
71 switch (field_order) {
72 case AV_FIELD_TB:
73 case AV_FIELD_TT: inter = 't'; break;
74 case AV_FIELD_BT:
75 case AV_FIELD_BB: inter = 'b'; break;
76 default: inter = 'p'; break;
77 }
78
79 switch (st->codecpar->format) {
80 case AV_PIX_FMT_GRAY8:
81 colorspace = " Cmono";
82 break;
83 case AV_PIX_FMT_GRAY9:
84 colorspace = " Cmono9";
85 break;
86 case AV_PIX_FMT_GRAY10:
87 colorspace = " Cmono10";
88 break;
89 case AV_PIX_FMT_GRAY12:
90 colorspace = " Cmono12";
91 break;
92 case AV_PIX_FMT_GRAY16:
93 colorspace = " Cmono16";
94 break;
95 case AV_PIX_FMT_YUV411P:
96 colorspace = " C411 XYSCSS=411";
97 break;
98 case AV_PIX_FMT_YUVJ420P:
99 colorspace = " C420jpeg XYSCSS=420JPEG";
100 colorrange = " XCOLORRANGE=FULL";
101 break;
102 case AV_PIX_FMT_YUVJ422P:
103 colorspace = " C422 XYSCSS=422";
104 colorrange = " XCOLORRANGE=FULL";
105 break;
106 case AV_PIX_FMT_YUVJ444P:
107 colorspace = " C444 XYSCSS=444";
108 colorrange = " XCOLORRANGE=FULL";
109 break;
110 case AV_PIX_FMT_YUV420P:
111 switch (st->codecpar->chroma_location) {
112 case AVCHROMA_LOC_TOPLEFT: colorspace = " C420paldv XYSCSS=420PALDV"; break;
113 case AVCHROMA_LOC_LEFT: colorspace = " C420mpeg2 XYSCSS=420MPEG2"; break;
114 default: colorspace = " C420jpeg XYSCSS=420JPEG"; break;
115 }
116 break;
117 case AV_PIX_FMT_YUV422P:
118 colorspace = " C422 XYSCSS=422";
119 break;
120 case AV_PIX_FMT_YUV444P:
121 colorspace = " C444 XYSCSS=444";
122 break;
123 case AV_PIX_FMT_YUV420P9:
124 colorspace = " C420p9 XYSCSS=420P9";
125 break;
126 case AV_PIX_FMT_YUV422P9:
127 colorspace = " C422p9 XYSCSS=422P9";
128 break;
129 case AV_PIX_FMT_YUV444P9:
130 colorspace = " C444p9 XYSCSS=444P9";
131 break;
132 case AV_PIX_FMT_YUV420P10:
133 colorspace = " C420p10 XYSCSS=420P10";
134 break;
135 case AV_PIX_FMT_YUV422P10:
136 colorspace = " C422p10 XYSCSS=422P10";
137 break;
138 case AV_PIX_FMT_YUV444P10:
139 colorspace = " C444p10 XYSCSS=444P10";
140 break;
141 case AV_PIX_FMT_YUV420P12:
142 colorspace = " C420p12 XYSCSS=420P12";
143 break;
144 case AV_PIX_FMT_YUV422P12:
145 colorspace = " C422p12 XYSCSS=422P12";
146 break;
147 case AV_PIX_FMT_YUV444P12:
148 colorspace = " C444p12 XYSCSS=444P12";
149 break;
150 case AV_PIX_FMT_YUV420P14:
151 colorspace = " C420p14 XYSCSS=420P14";
152 break;
153 case AV_PIX_FMT_YUV422P14:
154 colorspace = " C422p14 XYSCSS=422P14";
155 break;
156 case AV_PIX_FMT_YUV444P14:
157 colorspace = " C444p14 XYSCSS=444P14";
158 break;
159 case AV_PIX_FMT_YUV420P16:
160 colorspace = " C420p16 XYSCSS=420P16";
161 break;
162 case AV_PIX_FMT_YUV422P16:
163 colorspace = " C422p16 XYSCSS=422P16";
164 break;
165 case AV_PIX_FMT_YUV444P16:
166 colorspace = " C444p16 XYSCSS=444P16";
167 break;
168 }
169
170 ret = avio_printf(pb, Y4M_MAGIC " W%d H%d F%d:%d I%c A%d:%d%s%s\n",
171 width, height, raten, rated, inter,
172 aspectn, aspectd, colorspace, colorrange);
173 if (ret < 0) {
174 av_log(s, AV_LOG_ERROR,
175 "Error. YUV4MPEG stream header write failed.\n");
176 return ret;
177 }
178
179 return 0;
180 }
181
182
yuv4_write_packet(AVFormatContext * s,AVPacket * pkt)183 static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
184 {
185 AVStream *st = s->streams[pkt->stream_index];
186 AVIOContext *pb = s->pb;
187 const AVFrame *frame = (const AVFrame *)pkt->data;
188 int width, height, h_chroma_shift, v_chroma_shift;
189 int i;
190 const uint8_t *ptr, *ptr1, *ptr2;
191
192 /* construct frame header */
193
194 avio_printf(s->pb, Y4M_FRAME_MAGIC "\n");
195
196 width = st->codecpar->width;
197 height = st->codecpar->height;
198
199 ptr = frame->data[0];
200
201 switch (st->codecpar->format) {
202 case AV_PIX_FMT_GRAY8:
203 case AV_PIX_FMT_YUV411P:
204 case AV_PIX_FMT_YUV420P:
205 case AV_PIX_FMT_YUV422P:
206 case AV_PIX_FMT_YUV444P:
207 // TODO: remove YUVJ pixel formats when they are completely removed from the codebase.
208 case AV_PIX_FMT_YUVJ420P:
209 case AV_PIX_FMT_YUVJ422P:
210 case AV_PIX_FMT_YUVJ444P:
211 break;
212 case AV_PIX_FMT_GRAY9:
213 case AV_PIX_FMT_GRAY10:
214 case AV_PIX_FMT_GRAY12:
215 case AV_PIX_FMT_GRAY16:
216 case AV_PIX_FMT_YUV420P9:
217 case AV_PIX_FMT_YUV422P9:
218 case AV_PIX_FMT_YUV444P9:
219 case AV_PIX_FMT_YUV420P10:
220 case AV_PIX_FMT_YUV422P10:
221 case AV_PIX_FMT_YUV444P10:
222 case AV_PIX_FMT_YUV420P12:
223 case AV_PIX_FMT_YUV422P12:
224 case AV_PIX_FMT_YUV444P12:
225 case AV_PIX_FMT_YUV420P14:
226 case AV_PIX_FMT_YUV422P14:
227 case AV_PIX_FMT_YUV444P14:
228 case AV_PIX_FMT_YUV420P16:
229 case AV_PIX_FMT_YUV422P16:
230 case AV_PIX_FMT_YUV444P16:
231 width *= 2;
232 break;
233 default:
234 av_log(s, AV_LOG_ERROR, "The pixel format '%s' is not supported.\n",
235 av_get_pix_fmt_name(st->codecpar->format));
236 return AVERROR(EINVAL);
237 }
238
239 for (i = 0; i < height; i++) {
240 avio_write(pb, ptr, width);
241 ptr += frame->linesize[0];
242 }
243
244 if (st->codecpar->format != AV_PIX_FMT_GRAY8 && st->codecpar->format != AV_PIX_FMT_GRAY9 &&
245 st->codecpar->format != AV_PIX_FMT_GRAY10 && st->codecpar->format != AV_PIX_FMT_GRAY12 &&
246 st->codecpar->format != AV_PIX_FMT_GRAY16) {
247 // Adjust for smaller Cb and Cr planes
248 av_pix_fmt_get_chroma_sub_sample(st->codecpar->format, &h_chroma_shift,
249 &v_chroma_shift);
250 // Shift right, rounding up
251 width = AV_CEIL_RSHIFT(width, h_chroma_shift);
252 height = AV_CEIL_RSHIFT(height, v_chroma_shift);
253
254 ptr1 = frame->data[1];
255 ptr2 = frame->data[2];
256 for (i = 0; i < height; i++) { /* Cb */
257 avio_write(pb, ptr1, width);
258 ptr1 += frame->linesize[1];
259 }
260 for (i = 0; i < height; i++) { /* Cr */
261 avio_write(pb, ptr2, width);
262 ptr2 += frame->linesize[2];
263 }
264 }
265
266 return 0;
267 }
268
yuv4_init(AVFormatContext * s)269 static int yuv4_init(AVFormatContext *s)
270 {
271 if (s->nb_streams != 1)
272 return AVERROR(EIO);
273
274 if (s->streams[0]->codecpar->codec_id != AV_CODEC_ID_WRAPPED_AVFRAME) {
275 av_log(s, AV_LOG_ERROR, "ERROR: Codec not supported.\n");
276 return AVERROR_INVALIDDATA;
277 }
278
279 switch (s->streams[0]->codecpar->format) {
280 case AV_PIX_FMT_YUV411P:
281 av_log(s, AV_LOG_WARNING, "Warning: generating rarely used 4:1:1 YUV "
282 "stream, some mjpegtools might not work.\n");
283 break;
284 case AV_PIX_FMT_GRAY8:
285 case AV_PIX_FMT_YUV420P:
286 case AV_PIX_FMT_YUV422P:
287 case AV_PIX_FMT_YUV444P:
288 // TODO: remove YUVJ pixel formats when they are completely removed from the codebase.
289 case AV_PIX_FMT_YUVJ420P:
290 case AV_PIX_FMT_YUVJ422P:
291 case AV_PIX_FMT_YUVJ444P:
292 break;
293 case AV_PIX_FMT_GRAY9:
294 case AV_PIX_FMT_GRAY10:
295 case AV_PIX_FMT_GRAY12:
296 case AV_PIX_FMT_GRAY16:
297 case AV_PIX_FMT_YUV420P9:
298 case AV_PIX_FMT_YUV422P9:
299 case AV_PIX_FMT_YUV444P9:
300 case AV_PIX_FMT_YUV420P10:
301 case AV_PIX_FMT_YUV422P10:
302 case AV_PIX_FMT_YUV444P10:
303 case AV_PIX_FMT_YUV420P12:
304 case AV_PIX_FMT_YUV422P12:
305 case AV_PIX_FMT_YUV444P12:
306 case AV_PIX_FMT_YUV420P14:
307 case AV_PIX_FMT_YUV422P14:
308 case AV_PIX_FMT_YUV444P14:
309 case AV_PIX_FMT_YUV420P16:
310 case AV_PIX_FMT_YUV422P16:
311 case AV_PIX_FMT_YUV444P16:
312 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
313 av_log(s, AV_LOG_ERROR, "'%s' is not an official yuv4mpegpipe pixel format. "
314 "Use '-strict -1' to encode to this pixel format.\n",
315 av_get_pix_fmt_name(s->streams[0]->codecpar->format));
316 return AVERROR(EINVAL);
317 }
318 av_log(s, AV_LOG_WARNING, "Warning: generating non standard YUV stream. "
319 "Mjpegtools will not work.\n");
320 break;
321 default:
322 av_log(s, AV_LOG_ERROR, "ERROR: yuv4mpeg can only handle "
323 "yuv444p, yuv422p, yuv420p, yuv411p and gray8 pixel formats. "
324 "And using 'strict -1' also yuv444p9, yuv422p9, yuv420p9, "
325 "yuv444p10, yuv422p10, yuv420p10, "
326 "yuv444p12, yuv422p12, yuv420p12, "
327 "yuv444p14, yuv422p14, yuv420p14, "
328 "yuv444p16, yuv422p16, yuv420p16, "
329 "gray9, gray10, gray12 "
330 "and gray16 pixel formats. "
331 "Use -pix_fmt to select one.\n");
332 return AVERROR(EIO);
333 }
334
335 return 0;
336 }
337
338 AVOutputFormat ff_yuv4mpegpipe_muxer = {
339 .name = "yuv4mpegpipe",
340 .long_name = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe"),
341 .extensions = "y4m",
342 .audio_codec = AV_CODEC_ID_NONE,
343 .video_codec = AV_CODEC_ID_WRAPPED_AVFRAME,
344 .init = yuv4_init,
345 .write_header = yuv4_write_header,
346 .write_packet = yuv4_write_packet,
347 };
348