00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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;
00051
00052 inter = 'p';
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
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 ByteIOContext *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, m;
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
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 put_buffer(pb, buf2, strlen(buf2));
00112 }
00113 }
00114
00115
00116
00117 m = snprintf(buf1, sizeof(buf1), "%s\n", Y4M_FRAME_MAGIC);
00118 put_buffer(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 put_buffer(pb, ptr, width);
00126 ptr += picture->linesize[0];
00127 }
00128
00129 if (st->codec->pix_fmt != PIX_FMT_GRAY8){
00130
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++) {
00138 put_buffer(pb, ptr1, width);
00139 ptr1 += picture->linesize[1];
00140 }
00141 for(i=0;i<height;i++) {
00142 put_buffer(pb, ptr2, width);
00143 ptr2 += picture->linesize[2];
00144 }
00145 }
00146 put_flush_packet(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 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
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];
00193 char *tokstart,*tokend,*header_end;
00194 int i;
00195 ByteIOContext *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] = get_byte(pb);
00204 if (header[i] == '\n') {
00205 header[i+1] = 0x20;
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];
00216 for(tokstart = &header[strlen(Y4M_MAGIC) + 1]; tokstart < header_end; tokstart++) {
00217 if (*tokstart==0x20) continue;
00218 switch (*tokstart++) {
00219 case 'W':
00220 width = strtol(tokstart, &tokend, 10);
00221 tokstart=tokend;
00222 break;
00223 case 'H':
00224 height = strtol(tokstart, &tokend, 10);
00225 tokstart=tokend;
00226 break;
00227 case 'C':
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':
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':
00278 sscanf(tokstart,"%d:%d",&raten,&rated);
00279 while(tokstart<header_end&&*tokstart!=0x20) tokstart++;
00280 break;
00281 case 'A':
00282 sscanf(tokstart,"%d:%d",&aspectn,&aspectd);
00283 while(tokstart<header_end&&*tokstart!=0x20) tokstart++;
00284 break;
00285 case 'X':
00286 if (strncmp("YSCSS=",tokstart,6)==0) {
00287
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
00321 raten = 25;
00322 rated = 1;
00323 }
00324
00325 if (aspectn == 0 && aspectd == 0) {
00326
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] = get_byte(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
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 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