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