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 27static 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 179static 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 214static 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 285const 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