1/* 2 * YUV4MPEG demuxer 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 "avformat.h" 23#include "internal.h" 24#include "yuv4mpeg.h" 25 26/* Header size increased to allow room for optional flags */ 27#define MAX_YUV4_HEADER 80 28#define MAX_FRAME_HEADER 80 29 30static int yuv4_read_header(AVFormatContext *s) 31{ 32 char header[MAX_YUV4_HEADER + 10]; // Include headroom for 33 // the longest option 34 char *tokstart, *tokend, *header_end; 35 int i; 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; 41 AVStream *st; 42 enum AVFieldOrder field_order; 43 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. 49 header[i + 2] = 0; 50 break; 51 } 52 } 53 if (i == MAX_YUV4_HEADER) 54 return -1; 55 if (strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC))) 56 return -1; 57 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) 62 continue; 63 switch (*tokstart++) { 64 case 'W': // Width. Required. 65 width = strtol(tokstart, &tokend, 10); 66 tokstart = tokend; 67 break; 68 case 'H': // Height. Required. 69 height = strtol(tokstart, &tokend, 10); 70 tokstart = tokend; 71 break; 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"); 122 return -1; 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; 129 } else { 130 av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains an unknown " 131 "pixel format.\n"); 132 return -1; 133 } 134 while (tokstart < header_end && *tokstart != 0x20) 135 tokstart++; 136 break; 137 case 'I': // Interlace type 138 switch (*tokstart++){ 139 case '?': 140 field_order = AV_FIELD_UNKNOWN; 141 break; 142 case 'p': 143 field_order = AV_FIELD_PROGRESSIVE; 144 break; 145 case 't': 146 field_order = AV_FIELD_TT; 147 break; 148 case 'b': 149 field_order = AV_FIELD_BB; 150 break; 151 case 'm': 152 av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed " 153 "interlaced and non-interlaced frames.\n"); 154 default: 155 av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n"); 156 return AVERROR(EINVAL); 157 } 158 break; 159 case 'F': // Frame rate 160 sscanf(tokstart, "%d:%d", &raten, &rated); // 0:0 if unknown 161 while (tokstart < header_end && *tokstart != 0x20) 162 tokstart++; 163 break; 164 case 'A': // Pixel aspect 165 sscanf(tokstart, "%d:%d", &aspectn, &aspectd); // 0:0 if unknown 166 while (tokstart < header_end && *tokstart != 0x20) 167 tokstart++; 168 break; 169 case 'X': // Vendor extensions 170 if (strncmp("YSCSS=", tokstart, 6) == 0) { 171 // Older nonstandard pixel format representation 172 tokstart += 6; 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; 215 } 216 while (tokstart < header_end && *tokstart != 0x20) 217 tokstart++; 218 break; 219 } 220 } 221 222 if (width == -1 || height == -1) { 223 av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n"); 224 return -1; 225 } 226 227 if (pix_fmt == AV_PIX_FMT_NONE) { 228 if (alt_pix_fmt == AV_PIX_FMT_NONE) 229 pix_fmt = AV_PIX_FMT_YUV420P; 230 else 231 pix_fmt = alt_pix_fmt; 232 } 233 234 if (raten <= 0 || rated <= 0) { 235 // Frame rate unknown 236 raten = 25; 237 rated = 1; 238 } 239 240 if (aspectn == 0 && aspectd == 0) { 241 // Pixel aspect unknown 242 aspectd = 1; 243 } 244 245 st = avformat_new_stream(s, NULL); 246 if (!st) 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; 259 260 return 0; 261} 262 263static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt) 264{ 265 int i; 266 char header[MAX_FRAME_HEADER+1]; 267 int packet_size, width, height, ret; 268 AVStream *st = s->streams[0]; 269 270 for (i = 0; i < MAX_FRAME_HEADER; i++) { 271 header[i] = avio_r8(s->pb); 272 if (header[i] == '\n') { 273 header[i + 1] = 0; 274 break; 275 } 276 } 277 if (s->pb->error) 278 return s->pb->error; 279 else if (s->pb->eof_reached) 280 return AVERROR_EOF; 281 else if (i == MAX_FRAME_HEADER) 282 return AVERROR_INVALIDDATA; 283 284 if (strncmp(header, Y4M_FRAME_MAGIC, strlen(Y4M_FRAME_MAGIC))) 285 return AVERROR_INVALIDDATA; 286 287 width = st->codec->width; 288 height = st->codec->height; 289 290 packet_size = avpicture_get_size(st->codec->pix_fmt, width, height); 291 if (packet_size < 0) 292 return packet_size; 293 294 ret = av_get_packet(s->pb, pkt, packet_size); 295 if (ret < 0) 296 return ret; 297 else if (ret != packet_size) 298 return s->pb->eof_reached ? AVERROR_EOF : AVERROR(EIO); 299 300 pkt->stream_index = 0; 301 return 0; 302} 303 304static int yuv4_probe(AVProbeData *pd) 305{ 306 /* check file header */ 307 if (strncmp(pd->buf, Y4M_MAGIC, sizeof(Y4M_MAGIC) - 1) == 0) 308 return AVPROBE_SCORE_MAX; 309 else 310 return 0; 311} 312 313AVInputFormat 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, 319 .extensions = "y4m", 320}; 321