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