Libav 0.7.1
|
00001 /* 00002 * YUV4MPEG format 00003 * Copyright (c) 2001, 2002, 2003 Fabrice Bellard 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 #include "avformat.h" 00022 00023 #define Y4M_MAGIC "YUV4MPEG2" 00024 #define Y4M_FRAME_MAGIC "FRAME" 00025 #define Y4M_LINE_MAX 256 00026 00027 struct frame_attributes { 00028 int interlaced_frame; 00029 int top_field_first; 00030 }; 00031 00032 #if CONFIG_YUV4MPEGPIPE_MUXER 00033 static int yuv4_generate_header(AVFormatContext *s, char* buf) 00034 { 00035 AVStream *st; 00036 int width, height; 00037 int raten, rated, aspectn, aspectd, n; 00038 char inter; 00039 const char *colorspace = ""; 00040 00041 st = s->streams[0]; 00042 width = st->codec->width; 00043 height = st->codec->height; 00044 00045 av_reduce(&raten, &rated, st->codec->time_base.den, st->codec->time_base.num, (1UL<<31)-1); 00046 00047 aspectn = st->sample_aspect_ratio.num; 00048 aspectd = st->sample_aspect_ratio.den; 00049 00050 if ( aspectn == 0 && aspectd == 1 ) aspectd = 0; // 0:0 means unknown 00051 00052 inter = 'p'; /* progressive is the default */ 00053 if (st->codec->coded_frame && st->codec->coded_frame->interlaced_frame) { 00054 inter = st->codec->coded_frame->top_field_first ? 't' : 'b'; 00055 } 00056 00057 switch(st->codec->pix_fmt) { 00058 case PIX_FMT_GRAY8: 00059 colorspace = " Cmono"; 00060 break; 00061 case PIX_FMT_YUV411P: 00062 colorspace = " C411 XYSCSS=411"; 00063 break; 00064 case PIX_FMT_YUV420P: 00065 colorspace = (st->codec->chroma_sample_location == AVCHROMA_LOC_TOPLEFT)?" C420paldv XYSCSS=420PALDV": 00066 (st->codec->chroma_sample_location == AVCHROMA_LOC_LEFT) ?" C420mpeg2 XYSCSS=420MPEG2": 00067 " C420jpeg XYSCSS=420JPEG"; 00068 break; 00069 case PIX_FMT_YUV422P: 00070 colorspace = " C422 XYSCSS=422"; 00071 break; 00072 case PIX_FMT_YUV444P: 00073 colorspace = " C444 XYSCSS=444"; 00074 break; 00075 } 00076 00077 /* construct stream header, if this is the first frame */ 00078 n = snprintf(buf, Y4M_LINE_MAX, "%s W%d H%d F%d:%d I%c A%d:%d%s\n", 00079 Y4M_MAGIC, 00080 width, 00081 height, 00082 raten, rated, 00083 inter, 00084 aspectn, aspectd, 00085 colorspace); 00086 00087 return n; 00088 } 00089 00090 static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) 00091 { 00092 AVStream *st = s->streams[pkt->stream_index]; 00093 AVIOContext *pb = s->pb; 00094 AVPicture *picture; 00095 int* first_pkt = s->priv_data; 00096 int width, height, h_chroma_shift, v_chroma_shift; 00097 int i; 00098 char buf2[Y4M_LINE_MAX+1]; 00099 char buf1[20]; 00100 uint8_t *ptr, *ptr1, *ptr2; 00101 00102 picture = (AVPicture *)pkt->data; 00103 00104 /* for the first packet we have to output the header as well */ 00105 if (*first_pkt) { 00106 *first_pkt = 0; 00107 if (yuv4_generate_header(s, buf2) < 0) { 00108 av_log(s, AV_LOG_ERROR, "Error. YUV4MPEG stream header write failed.\n"); 00109 return AVERROR(EIO); 00110 } else { 00111 avio_write(pb, buf2, strlen(buf2)); 00112 } 00113 } 00114 00115 /* construct frame header */ 00116 00117 snprintf(buf1, sizeof(buf1), "%s\n", Y4M_FRAME_MAGIC); 00118 avio_write(pb, buf1, strlen(buf1)); 00119 00120 width = st->codec->width; 00121 height = st->codec->height; 00122 00123 ptr = picture->data[0]; 00124 for(i=0;i<height;i++) { 00125 avio_write(pb, ptr, width); 00126 ptr += picture->linesize[0]; 00127 } 00128 00129 if (st->codec->pix_fmt != PIX_FMT_GRAY8){ 00130 // Adjust for smaller Cb and Cr planes 00131 avcodec_get_chroma_sub_sample(st->codec->pix_fmt, &h_chroma_shift, &v_chroma_shift); 00132 width >>= h_chroma_shift; 00133 height >>= v_chroma_shift; 00134 00135 ptr1 = picture->data[1]; 00136 ptr2 = picture->data[2]; 00137 for(i=0;i<height;i++) { /* Cb */ 00138 avio_write(pb, ptr1, width); 00139 ptr1 += picture->linesize[1]; 00140 } 00141 for(i=0;i<height;i++) { /* Cr */ 00142 avio_write(pb, ptr2, width); 00143 ptr2 += picture->linesize[2]; 00144 } 00145 } 00146 avio_flush(pb); 00147 return 0; 00148 } 00149 00150 static int yuv4_write_header(AVFormatContext *s) 00151 { 00152 int* first_pkt = s->priv_data; 00153 00154 if (s->nb_streams != 1) 00155 return AVERROR(EIO); 00156 00157 if (s->streams[0]->codec->pix_fmt == PIX_FMT_YUV411P) { 00158 av_log(s, AV_LOG_ERROR, "Warning: generating rarely used 4:1:1 YUV stream, some mjpegtools might not work.\n"); 00159 } 00160 else if ((s->streams[0]->codec->pix_fmt != PIX_FMT_YUV420P) && 00161 (s->streams[0]->codec->pix_fmt != PIX_FMT_YUV422P) && 00162 (s->streams[0]->codec->pix_fmt != PIX_FMT_GRAY8) && 00163 (s->streams[0]->codec->pix_fmt != PIX_FMT_YUV444P)) { 00164 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"); 00165 return AVERROR(EIO); 00166 } 00167 00168 *first_pkt = 1; 00169 return 0; 00170 } 00171 00172 AVOutputFormat ff_yuv4mpegpipe_muxer = { 00173 "yuv4mpegpipe", 00174 NULL_IF_CONFIG_SMALL("YUV4MPEG pipe format"), 00175 "", 00176 "y4m", 00177 sizeof(int), 00178 CODEC_ID_NONE, 00179 CODEC_ID_RAWVIDEO, 00180 yuv4_write_header, 00181 yuv4_write_packet, 00182 .flags = AVFMT_RAWPICTURE, 00183 }; 00184 #endif 00185 00186 /* Header size increased to allow room for optional flags */ 00187 #define MAX_YUV4_HEADER 80 00188 #define MAX_FRAME_HEADER 80 00189 00190 static int yuv4_read_header(AVFormatContext *s, AVFormatParameters *ap) 00191 { 00192 char header[MAX_YUV4_HEADER+10]; // Include headroom for the longest option 00193 char *tokstart,*tokend,*header_end; 00194 int i; 00195 AVIOContext *pb = s->pb; 00196 int width=-1, height=-1, raten=0, rated=0, aspectn=0, aspectd=0; 00197 enum PixelFormat pix_fmt=PIX_FMT_NONE,alt_pix_fmt=PIX_FMT_NONE; 00198 enum AVChromaLocation chroma_sample_location = AVCHROMA_LOC_UNSPECIFIED; 00199 AVStream *st; 00200 struct frame_attributes *s1 = s->priv_data; 00201 00202 for (i=0; i<MAX_YUV4_HEADER; i++) { 00203 header[i] = avio_r8(pb); 00204 if (header[i] == '\n') { 00205 header[i+1] = 0x20; // Add a space after last option. Makes parsing "444" vs "444alpha" easier. 00206 header[i+2] = 0; 00207 break; 00208 } 00209 } 00210 if (i == MAX_YUV4_HEADER) return -1; 00211 if (strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC))) return -1; 00212 00213 s1->interlaced_frame = 0; 00214 s1->top_field_first = 0; 00215 header_end = &header[i+1]; // Include space 00216 for(tokstart = &header[strlen(Y4M_MAGIC) + 1]; tokstart < header_end; tokstart++) { 00217 if (*tokstart==0x20) continue; 00218 switch (*tokstart++) { 00219 case 'W': // Width. Required. 00220 width = strtol(tokstart, &tokend, 10); 00221 tokstart=tokend; 00222 break; 00223 case 'H': // Height. Required. 00224 height = strtol(tokstart, &tokend, 10); 00225 tokstart=tokend; 00226 break; 00227 case 'C': // Color space 00228 if (strncmp("420jpeg",tokstart,7)==0) { 00229 pix_fmt = PIX_FMT_YUV420P; 00230 chroma_sample_location = AVCHROMA_LOC_CENTER; 00231 } else if (strncmp("420mpeg2",tokstart,8)==0) { 00232 pix_fmt = PIX_FMT_YUV420P; 00233 chroma_sample_location = AVCHROMA_LOC_LEFT; 00234 } else if (strncmp("420paldv", tokstart, 8)==0) { 00235 pix_fmt = PIX_FMT_YUV420P; 00236 chroma_sample_location = AVCHROMA_LOC_TOPLEFT; 00237 } else if (strncmp("411", tokstart, 3)==0) 00238 pix_fmt = PIX_FMT_YUV411P; 00239 else if (strncmp("422", tokstart, 3)==0) 00240 pix_fmt = PIX_FMT_YUV422P; 00241 else if (strncmp("444alpha", tokstart, 8)==0) { 00242 av_log(s, AV_LOG_ERROR, "Cannot handle 4:4:4:4 YUV4MPEG stream.\n"); 00243 return -1; 00244 } else if (strncmp("444", tokstart, 3)==0) 00245 pix_fmt = PIX_FMT_YUV444P; 00246 else if (strncmp("mono",tokstart, 4)==0) { 00247 pix_fmt = PIX_FMT_GRAY8; 00248 } else { 00249 av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains an unknown pixel format.\n"); 00250 return -1; 00251 } 00252 while(tokstart<header_end&&*tokstart!=0x20) tokstart++; 00253 break; 00254 case 'I': // Interlace type 00255 switch (*tokstart++){ 00256 case '?': 00257 break; 00258 case 'p': 00259 s1->interlaced_frame=0; 00260 break; 00261 case 't': 00262 s1->interlaced_frame=1; 00263 s1->top_field_first=1; 00264 break; 00265 case 'b': 00266 s1->interlaced_frame=1; 00267 s1->top_field_first=0; 00268 break; 00269 case 'm': 00270 av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed interlaced and non-interlaced frames.\n"); 00271 return -1; 00272 default: 00273 av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n"); 00274 return -1; 00275 } 00276 break; 00277 case 'F': // Frame rate 00278 sscanf(tokstart,"%d:%d",&raten,&rated); // 0:0 if unknown 00279 while(tokstart<header_end&&*tokstart!=0x20) tokstart++; 00280 break; 00281 case 'A': // Pixel aspect 00282 sscanf(tokstart,"%d:%d",&aspectn,&aspectd); // 0:0 if unknown 00283 while(tokstart<header_end&&*tokstart!=0x20) tokstart++; 00284 break; 00285 case 'X': // Vendor extensions 00286 if (strncmp("YSCSS=",tokstart,6)==0) { 00287 // Older nonstandard pixel format representation 00288 tokstart+=6; 00289 if (strncmp("420JPEG",tokstart,7)==0) 00290 alt_pix_fmt=PIX_FMT_YUV420P; 00291 else if (strncmp("420MPEG2",tokstart,8)==0) 00292 alt_pix_fmt=PIX_FMT_YUV420P; 00293 else if (strncmp("420PALDV",tokstart,8)==0) 00294 alt_pix_fmt=PIX_FMT_YUV420P; 00295 else if (strncmp("411",tokstart,3)==0) 00296 alt_pix_fmt=PIX_FMT_YUV411P; 00297 else if (strncmp("422",tokstart,3)==0) 00298 alt_pix_fmt=PIX_FMT_YUV422P; 00299 else if (strncmp("444",tokstart,3)==0) 00300 alt_pix_fmt=PIX_FMT_YUV444P; 00301 } 00302 while(tokstart<header_end&&*tokstart!=0x20) tokstart++; 00303 break; 00304 } 00305 } 00306 00307 if ((width == -1) || (height == -1)) { 00308 av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n"); 00309 return -1; 00310 } 00311 00312 if (pix_fmt == PIX_FMT_NONE) { 00313 if (alt_pix_fmt == PIX_FMT_NONE) 00314 pix_fmt = PIX_FMT_YUV420P; 00315 else 00316 pix_fmt = alt_pix_fmt; 00317 } 00318 00319 if (raten <= 0 || rated <= 0) { 00320 // Frame rate unknown 00321 raten = 25; 00322 rated = 1; 00323 } 00324 00325 if (aspectn == 0 && aspectd == 0) { 00326 // Pixel aspect unknown 00327 aspectd = 1; 00328 } 00329 00330 st = av_new_stream(s, 0); 00331 if(!st) 00332 return AVERROR(ENOMEM); 00333 st->codec->width = width; 00334 st->codec->height = height; 00335 av_reduce(&raten, &rated, raten, rated, (1UL<<31)-1); 00336 av_set_pts_info(st, 64, rated, raten); 00337 st->codec->pix_fmt = pix_fmt; 00338 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00339 st->codec->codec_id = CODEC_ID_RAWVIDEO; 00340 st->sample_aspect_ratio= (AVRational){aspectn, aspectd}; 00341 st->codec->chroma_sample_location = chroma_sample_location; 00342 00343 return 0; 00344 } 00345 00346 static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt) 00347 { 00348 int i; 00349 char header[MAX_FRAME_HEADER+1]; 00350 int packet_size, width, height; 00351 AVStream *st = s->streams[0]; 00352 struct frame_attributes *s1 = s->priv_data; 00353 00354 for (i=0; i<MAX_FRAME_HEADER; i++) { 00355 header[i] = avio_r8(s->pb); 00356 if (header[i] == '\n') { 00357 header[i+1] = 0; 00358 break; 00359 } 00360 } 00361 if (i == MAX_FRAME_HEADER) return -1; 00362 if (strncmp(header, Y4M_FRAME_MAGIC, strlen(Y4M_FRAME_MAGIC))) return -1; 00363 00364 width = st->codec->width; 00365 height = st->codec->height; 00366 00367 packet_size = avpicture_get_size(st->codec->pix_fmt, width, height); 00368 if (packet_size < 0) 00369 return -1; 00370 00371 if (av_get_packet(s->pb, pkt, packet_size) != packet_size) 00372 return AVERROR(EIO); 00373 00374 if (s->streams[0]->codec->coded_frame) { 00375 s->streams[0]->codec->coded_frame->interlaced_frame = s1->interlaced_frame; 00376 s->streams[0]->codec->coded_frame->top_field_first = s1->top_field_first; 00377 } 00378 00379 pkt->stream_index = 0; 00380 return 0; 00381 } 00382 00383 static int yuv4_probe(AVProbeData *pd) 00384 { 00385 /* check file header */ 00386 if (strncmp(pd->buf, Y4M_MAGIC, sizeof(Y4M_MAGIC)-1)==0) 00387 return AVPROBE_SCORE_MAX; 00388 else 00389 return 0; 00390 } 00391 00392 #if CONFIG_YUV4MPEGPIPE_DEMUXER 00393 AVInputFormat ff_yuv4mpegpipe_demuxer = { 00394 "yuv4mpegpipe", 00395 NULL_IF_CONFIG_SMALL("YUV4MPEG pipe format"), 00396 sizeof(struct frame_attributes), 00397 yuv4_probe, 00398 yuv4_read_header, 00399 yuv4_read_packet, 00400 .extensions = "y4m" 00401 }; 00402 #endif