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 switch(st->codecpar->color_range) {
54 case AVCOL_RANGE_MPEG:
55 colorrange = " XCOLORRANGE=LIMITED";
56 break;
57 case AVCOL_RANGE_JPEG:
58 colorrange = " XCOLORRANGE=FULL";
59 break;
60 default:
61 break;
62 }
63
64 switch (field_order) {
65 case AV_FIELD_TB:
66 case AV_FIELD_TT: inter = 't'; break;
67 case AV_FIELD_BT:
68 case AV_FIELD_BB: inter = 'b'; break;
69 default: inter = 'p'; break;
70 }
71
72 switch (st->codecpar->format) {
73 case AV_PIX_FMT_GRAY8:
74 colorspace = " Cmono";
75 break;
76 case AV_PIX_FMT_GRAY9:
77 colorspace = " Cmono9";
78 break;
79 case AV_PIX_FMT_GRAY10:
80 colorspace = " Cmono10";
81 break;
82 case AV_PIX_FMT_GRAY12:
83 colorspace = " Cmono12";
84 break;
85 case AV_PIX_FMT_GRAY16:
86 colorspace = " Cmono16";
87 break;
88 case AV_PIX_FMT_YUV411P:
89 colorspace = " C411 XYSCSS=411";
90 break;
91 case AV_PIX_FMT_YUVJ420P:
92 colorspace = " C420jpeg XYSCSS=420JPEG";
93 colorrange = " XCOLORRANGE=FULL";
94 break;
95 case AV_PIX_FMT_YUVJ422P:
96 colorspace = " C422 XYSCSS=422";
97 colorrange = " XCOLORRANGE=FULL";
98 break;
99 case AV_PIX_FMT_YUVJ444P:
100 colorspace = " C444 XYSCSS=444";
101 colorrange = " XCOLORRANGE=FULL";
102 break;
103 case AV_PIX_FMT_YUV420P:
104 switch (st->codecpar->chroma_location) {
105 case AVCHROMA_LOC_TOPLEFT: colorspace = " C420paldv XYSCSS=420PALDV"; break;
106 case AVCHROMA_LOC_LEFT: colorspace = " C420mpeg2 XYSCSS=420MPEG2"; break;
107 default: colorspace = " C420jpeg XYSCSS=420JPEG"; break;
108 }
109 break;
110 case AV_PIX_FMT_YUV422P:
111 colorspace = " C422 XYSCSS=422";
112 break;
113 case AV_PIX_FMT_YUV444P:
114 colorspace = " C444 XYSCSS=444";
115 break;
116 case AV_PIX_FMT_YUVA444P:
117 colorspace = " C444alpha XYSCSS=444";
118 break;
119 case AV_PIX_FMT_YUV420P9:
120 colorspace = " C420p9 XYSCSS=420P9";
121 break;
122 case AV_PIX_FMT_YUV422P9:
123 colorspace = " C422p9 XYSCSS=422P9";
124 break;
125 case AV_PIX_FMT_YUV444P9:
126 colorspace = " C444p9 XYSCSS=444P9";
127 break;
128 case AV_PIX_FMT_YUV420P10:
129 colorspace = " C420p10 XYSCSS=420P10";
130 break;
131 case AV_PIX_FMT_YUV422P10:
132 colorspace = " C422p10 XYSCSS=422P10";
133 break;
134 case AV_PIX_FMT_YUV444P10:
135 colorspace = " C444p10 XYSCSS=444P10";
136 break;
137 case AV_PIX_FMT_YUV420P12:
138 colorspace = " C420p12 XYSCSS=420P12";
139 break;
140 case AV_PIX_FMT_YUV422P12:
141 colorspace = " C422p12 XYSCSS=422P12";
142 break;
143 case AV_PIX_FMT_YUV444P12:
144 colorspace = " C444p12 XYSCSS=444P12";
145 break;
146 case AV_PIX_FMT_YUV420P14:
147 colorspace = " C420p14 XYSCSS=420P14";
148 break;
149 case AV_PIX_FMT_YUV422P14:
150 colorspace = " C422p14 XYSCSS=422P14";
151 break;
152 case AV_PIX_FMT_YUV444P14:
153 colorspace = " C444p14 XYSCSS=444P14";
154 break;
155 case AV_PIX_FMT_YUV420P16:
156 colorspace = " C420p16 XYSCSS=420P16";
157 break;
158 case AV_PIX_FMT_YUV422P16:
159 colorspace = " C422p16 XYSCSS=422P16";
160 break;
161 case AV_PIX_FMT_YUV444P16:
162 colorspace = " C444p16 XYSCSS=444P16";
163 break;
164 }
165
166 ret = avio_printf(pb, Y4M_MAGIC " W%d H%d F%d:%d I%c A%d:%d%s%s\n",
167 width, height, raten, rated, inter,
168 aspectn, aspectd, colorspace, colorrange);
169 if (ret < 0) {
170 av_log(s, AV_LOG_ERROR,
171 "Error. YUV4MPEG stream header write failed.\n");
172 return ret;
173 }
174
175 return 0;
176 }
177
178
yuv4_write_packet(AVFormatContext * s,AVPacket * pkt)179 static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
180 {
181 AVStream *st = s->streams[pkt->stream_index];
182 AVIOContext *pb = s->pb;
183 const AVFrame *frame = (const AVFrame *)pkt->data;
184 int width, height;
185 const AVPixFmtDescriptor *desc;
186
187 /* construct frame header */
188
189 avio_printf(s->pb, Y4M_FRAME_MAGIC "\n");
190
191 width = st->codecpar->width;
192 height = st->codecpar->height;
193 desc = av_pix_fmt_desc_get(st->codecpar->format);
194
195 /* The following code presumes all planes to be non-interleaved. */
196 for (int k = 0; k < desc->nb_components; k++) {
197 int plane_height = height, plane_width = width * desc->comp[k].step;
198 const uint8_t *ptr = frame->data[k];
199
200 if (desc->nb_components >= 3 && (k == 1 || k == 2)) { /* chroma? */
201 plane_width = AV_CEIL_RSHIFT(plane_width, desc->log2_chroma_w);
202 plane_height = AV_CEIL_RSHIFT(plane_height, desc->log2_chroma_h);
203 }
204
205 for (int i = 0; i < plane_height; i++) {
206 avio_write(pb, ptr, plane_width);
207 ptr += frame->linesize[k];
208 }
209 }
210
211 return 0;
212 }
213
yuv4_init(AVFormatContext * s)214 static int yuv4_init(AVFormatContext *s)
215 {
216 if (s->nb_streams != 1)
217 return AVERROR(EIO);
218
219 if (s->streams[0]->codecpar->codec_id != AV_CODEC_ID_WRAPPED_AVFRAME) {
220 av_log(s, AV_LOG_ERROR, "ERROR: Codec not supported.\n");
221 return AVERROR_INVALIDDATA;
222 }
223
224 switch (s->streams[0]->codecpar->format) {
225 case AV_PIX_FMT_YUV411P:
226 av_log(s, AV_LOG_WARNING, "Warning: generating rarely used 4:1:1 YUV "
227 "stream, some mjpegtools might not work.\n");
228 break;
229 case AV_PIX_FMT_GRAY8:
230 case AV_PIX_FMT_YUV420P:
231 case AV_PIX_FMT_YUV422P:
232 case AV_PIX_FMT_YUV444P:
233 // TODO: remove YUVJ pixel formats when they are completely removed from the codebase.
234 case AV_PIX_FMT_YUVJ420P:
235 case AV_PIX_FMT_YUVJ422P:
236 case AV_PIX_FMT_YUVJ444P:
237 break;
238 case AV_PIX_FMT_GRAY9:
239 case AV_PIX_FMT_GRAY10:
240 case AV_PIX_FMT_GRAY12:
241 case AV_PIX_FMT_GRAY16:
242 case AV_PIX_FMT_YUV420P9:
243 case AV_PIX_FMT_YUV422P9:
244 case AV_PIX_FMT_YUV444P9:
245 case AV_PIX_FMT_YUV420P10:
246 case AV_PIX_FMT_YUV422P10:
247 case AV_PIX_FMT_YUV444P10:
248 case AV_PIX_FMT_YUV420P12:
249 case AV_PIX_FMT_YUV422P12:
250 case AV_PIX_FMT_YUV444P12:
251 case AV_PIX_FMT_YUV420P14:
252 case AV_PIX_FMT_YUV422P14:
253 case AV_PIX_FMT_YUV444P14:
254 case AV_PIX_FMT_YUV420P16:
255 case AV_PIX_FMT_YUV422P16:
256 case AV_PIX_FMT_YUV444P16:
257 case AV_PIX_FMT_YUVA444P:
258 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
259 av_log(s, AV_LOG_ERROR, "'%s' is not an official yuv4mpegpipe pixel format. "
260 "Use '-strict -1' to encode to this pixel format.\n",
261 av_get_pix_fmt_name(s->streams[0]->codecpar->format));
262 return AVERROR(EINVAL);
263 }
264 av_log(s, AV_LOG_WARNING, "Warning: generating non standard YUV stream. "
265 "Mjpegtools will not work.\n");
266 break;
267 default:
268 av_log(s, AV_LOG_ERROR, "ERROR: yuv4mpeg can only handle "
269 "yuv444p, yuv422p, yuv420p, yuv411p and gray8 pixel formats. "
270 "And using 'strict -1' also yuv444p9, yuv422p9, yuv420p9, "
271 "yuv444p10, yuv422p10, yuv420p10, "
272 "yuv444p12, yuv422p12, yuv420p12, "
273 "yuv444p14, yuv422p14, yuv420p14, "
274 "yuv444p16, yuv422p16, yuv420p16, "
275 "yuva444p, "
276 "gray9, gray10, gray12 "
277 "and gray16 pixel formats. "
278 "Use -pix_fmt to select one.\n");
279 return AVERROR(EIO);
280 }
281
282 return 0;
283 }
284
285 const AVOutputFormat ff_yuv4mpegpipe_muxer = {
286 .name = "yuv4mpegpipe",
287 .long_name = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe"),
288 .extensions = "y4m",
289 .audio_codec = AV_CODEC_ID_NONE,
290 .video_codec = AV_CODEC_ID_WRAPPED_AVFRAME,
291 .init = yuv4_init,
292 .write_header = yuv4_write_header,
293 .write_packet = yuv4_write_packet,
294 };
295