1/* 2 * YUV4MPEG format 3 * Copyright (c) 2001, 2002, 2003 Fabrice Bellard 4 * 5 * This file is part of Libav. 6 * 7 * Libav 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 * Libav 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 Libav; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21#include "avformat.h" 22#include "internal.h" 23 24#define Y4M_MAGIC "YUV4MPEG2" 25#define Y4M_FRAME_MAGIC "FRAME" 26#define Y4M_LINE_MAX 256 27 28struct frame_attributes { 29 int interlaced_frame; 30 int top_field_first; 31}; 32 33#if CONFIG_YUV4MPEGPIPE_MUXER 34static int yuv4_generate_header(AVFormatContext *s, char* buf) 35{ 36 AVStream *st; 37 int width, height; 38 int raten, rated, aspectn, aspectd, n; 39 char inter; 40 const char *colorspace = ""; 41 42 st = s->streams[0]; 43 width = st->codec->width; 44 height = st->codec->height; 45 46 av_reduce(&raten, &rated, st->codec->time_base.den, 47 st->codec->time_base.num, (1UL << 31) - 1); 48 49 aspectn = st->sample_aspect_ratio.num; 50 aspectd = st->sample_aspect_ratio.den; 51 52 if (aspectn == 0 && aspectd == 1) 53 aspectd = 0; // 0:0 means unknown 54 55 inter = 'p'; /* progressive is the default */ 56 if (st->codec->coded_frame && st->codec->coded_frame->interlaced_frame) 57 inter = st->codec->coded_frame->top_field_first ? 't' : 'b'; 58 59 switch (st->codec->pix_fmt) { 60 case PIX_FMT_GRAY8: 61 colorspace = " Cmono"; 62 break; 63 case PIX_FMT_YUV411P: 64 colorspace = " C411 XYSCSS=411"; 65 break; 66 case PIX_FMT_YUV420P: 67 switch (st->codec->chroma_sample_location) { 68 case AVCHROMA_LOC_TOPLEFT: colorspace = " C420paldv XYSCSS=420PALDV"; break; 69 case AVCHROMA_LOC_LEFT: colorspace = " C420mpeg2 XYSCSS=420MPEG2"; break; 70 default: colorspace = " C420jpeg XYSCSS=420JPEG"; break; 71 } 72 break; 73 case PIX_FMT_YUV422P: 74 colorspace = " C422 XYSCSS=422"; 75 break; 76 case PIX_FMT_YUV444P: 77 colorspace = " C444 XYSCSS=444"; 78 break; 79 } 80 81 /* construct stream header, if this is the first frame */ 82 n = snprintf(buf, Y4M_LINE_MAX, "%s W%d H%d F%d:%d I%c A%d:%d%s\n", 83 Y4M_MAGIC, width, height, raten, rated, inter, 84 aspectn, aspectd, colorspace); 85 86 return n; 87} 88 89static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) 90{ 91 AVStream *st = s->streams[pkt->stream_index]; 92 AVIOContext *pb = s->pb; 93 AVPicture *picture; 94 int* first_pkt = s->priv_data; 95 int width, height, h_chroma_shift, v_chroma_shift; 96 int i; 97 char buf2[Y4M_LINE_MAX + 1]; 98 char buf1[20]; 99 uint8_t *ptr, *ptr1, *ptr2; 100 101 picture = (AVPicture *)pkt->data; 102 103 /* for the first packet we have to output the header as well */ 104 if (*first_pkt) { 105 *first_pkt = 0; 106 if (yuv4_generate_header(s, buf2) < 0) { 107 av_log(s, AV_LOG_ERROR, 108 "Error. YUV4MPEG stream header write failed.\n"); 109 return AVERROR(EIO); 110 } else { 111 avio_write(pb, buf2, strlen(buf2)); 112 } 113 } 114 115 /* construct frame header */ 116 117 snprintf(buf1, sizeof(buf1), "%s\n", Y4M_FRAME_MAGIC); 118 avio_write(pb, buf1, strlen(buf1)); 119 120 width = st->codec->width; 121 height = st->codec->height; 122 123 ptr = picture->data[0]; 124 for (i = 0; i < height; i++) { 125 avio_write(pb, ptr, width); 126 ptr += picture->linesize[0]; 127 } 128 129 if (st->codec->pix_fmt != PIX_FMT_GRAY8) { 130 // Adjust for smaller Cb and Cr planes 131 avcodec_get_chroma_sub_sample(st->codec->pix_fmt, &h_chroma_shift, 132 &v_chroma_shift); 133 width >>= h_chroma_shift; 134 height >>= v_chroma_shift; 135 136 ptr1 = picture->data[1]; 137 ptr2 = picture->data[2]; 138 for (i = 0; i < height; i++) { /* Cb */ 139 avio_write(pb, ptr1, width); 140 ptr1 += picture->linesize[1]; 141 } 142 for (i = 0; i < height; i++) { /* Cr */ 143 avio_write(pb, ptr2, width); 144 ptr2 += picture->linesize[2]; 145 } 146 } 147 avio_flush(pb); 148 return 0; 149} 150 151static int yuv4_write_header(AVFormatContext *s) 152{ 153 int *first_pkt = s->priv_data; 154 155 if (s->nb_streams != 1) 156 return AVERROR(EIO); 157 158 if (s->streams[0]->codec->codec_id != CODEC_ID_RAWVIDEO) { 159 av_log(s, AV_LOG_ERROR, "ERROR: Only rawvideo supported.\n"); 160 return AVERROR_INVALIDDATA; 161 } 162 163 if (s->streams[0]->codec->pix_fmt == PIX_FMT_YUV411P) { 164 av_log(s, AV_LOG_ERROR, "Warning: generating rarely used 4:1:1 YUV " 165 "stream, some mjpegtools might not work.\n"); 166 } else if ((s->streams[0]->codec->pix_fmt != PIX_FMT_YUV420P) && 167 (s->streams[0]->codec->pix_fmt != PIX_FMT_YUV422P) && 168 (s->streams[0]->codec->pix_fmt != PIX_FMT_GRAY8) && 169 (s->streams[0]->codec->pix_fmt != PIX_FMT_YUV444P)) { 170 av_log(s, AV_LOG_ERROR, "ERROR: yuv4mpeg only handles yuv444p, " 171 "yuv422p, yuv420p, yuv411p and gray pixel formats. " 172 "Use -pix_fmt to select one.\n"); 173 return AVERROR(EIO); 174 } 175 176 *first_pkt = 1; 177 return 0; 178} 179 180AVOutputFormat ff_yuv4mpegpipe_muxer = { 181 .name = "yuv4mpegpipe", 182 .long_name = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe format"), 183 .mime_type = "", 184 .extensions = "y4m", 185 .priv_data_size = sizeof(int), 186 .audio_codec = CODEC_ID_NONE, 187 .video_codec = CODEC_ID_RAWVIDEO, 188 .write_header = yuv4_write_header, 189 .write_packet = yuv4_write_packet, 190 .flags = AVFMT_RAWPICTURE, 191}; 192#endif 193 194/* Header size increased to allow room for optional flags */ 195#define MAX_YUV4_HEADER 80 196#define MAX_FRAME_HEADER 80 197 198static int yuv4_read_header(AVFormatContext *s, AVFormatParameters *ap) 199{ 200 char header[MAX_YUV4_HEADER + 10]; // Include headroom for 201 // the longest option 202 char *tokstart, *tokend, *header_end; 203 int i; 204 AVIOContext *pb = s->pb; 205 int width = -1, height = -1, raten = 0, 206 rated = 0, aspectn = 0, aspectd = 0; 207 enum PixelFormat pix_fmt = PIX_FMT_NONE, alt_pix_fmt = PIX_FMT_NONE; 208 enum AVChromaLocation chroma_sample_location = AVCHROMA_LOC_UNSPECIFIED; 209 AVStream *st; 210 struct frame_attributes *s1 = s->priv_data; 211 212 for (i = 0; i < MAX_YUV4_HEADER; i++) { 213 header[i] = avio_r8(pb); 214 if (header[i] == '\n') { 215 header[i + 1] = 0x20; // Add a space after last option. 216 // Makes parsing "444" vs "444alpha" easier. 217 header[i + 2] = 0; 218 break; 219 } 220 } 221 if (i == MAX_YUV4_HEADER) 222 return -1; 223 if (strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC))) 224 return -1; 225 226 s1->interlaced_frame = 0; 227 s1->top_field_first = 0; 228 header_end = &header[i + 1]; // Include space 229 for (tokstart = &header[strlen(Y4M_MAGIC) + 1]; 230 tokstart < header_end; tokstart++) { 231 if (*tokstart == 0x20) 232 continue; 233 switch (*tokstart++) { 234 case 'W': // Width. Required. 235 width = strtol(tokstart, &tokend, 10); 236 tokstart = tokend; 237 break; 238 case 'H': // Height. Required. 239 height = strtol(tokstart, &tokend, 10); 240 tokstart = tokend; 241 break; 242 case 'C': // Color space 243 if (strncmp("420jpeg", tokstart, 7) == 0) { 244 pix_fmt = PIX_FMT_YUV420P; 245 chroma_sample_location = AVCHROMA_LOC_CENTER; 246 } else if (strncmp("420mpeg2", tokstart, 8) == 0) { 247 pix_fmt = PIX_FMT_YUV420P; 248 chroma_sample_location = AVCHROMA_LOC_LEFT; 249 } else if (strncmp("420paldv", tokstart, 8) == 0) { 250 pix_fmt = PIX_FMT_YUV420P; 251 chroma_sample_location = AVCHROMA_LOC_TOPLEFT; 252 } else if (strncmp("411", tokstart, 3) == 0) 253 pix_fmt = PIX_FMT_YUV411P; 254 else if (strncmp("422", tokstart, 3) == 0) 255 pix_fmt = PIX_FMT_YUV422P; 256 else if (strncmp("444alpha", tokstart, 8) == 0 ) { 257 av_log(s, AV_LOG_ERROR, "Cannot handle 4:4:4:4 " 258 "YUV4MPEG stream.\n"); 259 return -1; 260 } else if (strncmp("444", tokstart, 3) == 0) 261 pix_fmt = PIX_FMT_YUV444P; 262 else if (strncmp("mono", tokstart, 4) == 0) { 263 pix_fmt = PIX_FMT_GRAY8; 264 } else { 265 av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains an unknown " 266 "pixel format.\n"); 267 return -1; 268 } 269 while (tokstart < header_end && *tokstart != 0x20) 270 tokstart++; 271 break; 272 case 'I': // Interlace type 273 switch (*tokstart++){ 274 case '?': 275 break; 276 case 'p': 277 s1->interlaced_frame = 0; 278 break; 279 case 't': 280 s1->interlaced_frame = 1; 281 s1->top_field_first = 1; 282 break; 283 case 'b': 284 s1->interlaced_frame = 1; 285 s1->top_field_first = 0; 286 break; 287 case 'm': 288 av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed " 289 "interlaced and non-interlaced frames.\n"); 290 return -1; 291 default: 292 av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n"); 293 return -1; 294 } 295 break; 296 case 'F': // Frame rate 297 sscanf(tokstart, "%d:%d", &raten, &rated); // 0:0 if unknown 298 while (tokstart < header_end && *tokstart != 0x20) 299 tokstart++; 300 break; 301 case 'A': // Pixel aspect 302 sscanf(tokstart, "%d:%d", &aspectn, &aspectd); // 0:0 if unknown 303 while (tokstart < header_end && *tokstart != 0x20) 304 tokstart++; 305 break; 306 case 'X': // Vendor extensions 307 if (strncmp("YSCSS=", tokstart, 6) == 0) { 308 // Older nonstandard pixel format representation 309 tokstart += 6; 310 if (strncmp("420JPEG", tokstart, 7) == 0) 311 alt_pix_fmt = PIX_FMT_YUV420P; 312 else if (strncmp("420MPEG2", tokstart, 8) == 0) 313 alt_pix_fmt = PIX_FMT_YUV420P; 314 else if (strncmp("420PALDV", tokstart, 8) == 0) 315 alt_pix_fmt = PIX_FMT_YUV420P; 316 else if (strncmp("411", tokstart, 3) == 0) 317 alt_pix_fmt = PIX_FMT_YUV411P; 318 else if (strncmp("422", tokstart, 3) == 0) 319 alt_pix_fmt = PIX_FMT_YUV422P; 320 else if (strncmp("444", tokstart, 3) == 0) 321 alt_pix_fmt = PIX_FMT_YUV444P; 322 } 323 while (tokstart < header_end && *tokstart != 0x20) 324 tokstart++; 325 break; 326 } 327 } 328 329 if (width == -1 || height == -1) { 330 av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n"); 331 return -1; 332 } 333 334 if (pix_fmt == PIX_FMT_NONE) { 335 if (alt_pix_fmt == PIX_FMT_NONE) 336 pix_fmt = PIX_FMT_YUV420P; 337 else 338 pix_fmt = alt_pix_fmt; 339 } 340 341 if (raten <= 0 || rated <= 0) { 342 // Frame rate unknown 343 raten = 25; 344 rated = 1; 345 } 346 347 if (aspectn == 0 && aspectd == 0) { 348 // Pixel aspect unknown 349 aspectd = 1; 350 } 351 352 st = avformat_new_stream(s, NULL); 353 if (!st) 354 return AVERROR(ENOMEM); 355 st->codec->width = width; 356 st->codec->height = height; 357 av_reduce(&raten, &rated, raten, rated, (1UL << 31) - 1); 358 avpriv_set_pts_info(st, 64, rated, raten); 359 st->codec->pix_fmt = pix_fmt; 360 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 361 st->codec->codec_id = CODEC_ID_RAWVIDEO; 362 st->sample_aspect_ratio = (AVRational){ aspectn, aspectd }; 363 st->codec->chroma_sample_location = chroma_sample_location; 364 365 return 0; 366} 367 368static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt) 369{ 370 int i; 371 char header[MAX_FRAME_HEADER+1]; 372 int packet_size, width, height, ret; 373 AVStream *st = s->streams[0]; 374 struct frame_attributes *s1 = s->priv_data; 375 376 for (i = 0; i < MAX_FRAME_HEADER; i++) { 377 header[i] = avio_r8(s->pb); 378 if (header[i] == '\n') { 379 header[i + 1] = 0; 380 break; 381 } 382 } 383 if (s->pb->error) 384 return s->pb->error; 385 else if (s->pb->eof_reached) 386 return AVERROR_EOF; 387 else if (i == MAX_FRAME_HEADER) 388 return AVERROR_INVALIDDATA; 389 390 if (strncmp(header, Y4M_FRAME_MAGIC, strlen(Y4M_FRAME_MAGIC))) 391 return AVERROR_INVALIDDATA; 392 393 width = st->codec->width; 394 height = st->codec->height; 395 396 packet_size = avpicture_get_size(st->codec->pix_fmt, width, height); 397 if (packet_size < 0) 398 return packet_size; 399 400 ret = av_get_packet(s->pb, pkt, packet_size); 401 if (ret < 0) 402 return ret; 403 else if (ret != packet_size) 404 return s->pb->eof_reached ? AVERROR_EOF : AVERROR(EIO); 405 406 if (st->codec->coded_frame) { 407 st->codec->coded_frame->interlaced_frame = s1->interlaced_frame; 408 st->codec->coded_frame->top_field_first = s1->top_field_first; 409 } 410 411 pkt->stream_index = 0; 412 return 0; 413} 414 415static int yuv4_probe(AVProbeData *pd) 416{ 417 /* check file header */ 418 if (strncmp(pd->buf, Y4M_MAGIC, sizeof(Y4M_MAGIC) - 1) == 0) 419 return AVPROBE_SCORE_MAX; 420 else 421 return 0; 422} 423 424#if CONFIG_YUV4MPEGPIPE_DEMUXER 425AVInputFormat ff_yuv4mpegpipe_demuxer = { 426 .name = "yuv4mpegpipe", 427 .long_name = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe format"), 428 .priv_data_size = sizeof(struct frame_attributes), 429 .read_probe = yuv4_probe, 430 .read_header = yuv4_read_header, 431 .read_packet = yuv4_read_packet, 432 .extensions = "y4m" 433}; 434#endif 435