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 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
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
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
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 avio_write(pb, ptr1, width);
00139 ptr1 += picture->linesize[1];
00140 }
00141 for(i=0;i<height;i++) {
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->codec_id != CODEC_ID_RAWVIDEO) {
00158 av_log(s, AV_LOG_ERROR, "ERROR: Only rawvideo supported.\n");
00159 return AVERROR_INVALIDDATA;
00160 }
00161
00162 if (s->streams[0]->codec->pix_fmt == PIX_FMT_YUV411P) {
00163 av_log(s, AV_LOG_ERROR, "Warning: generating rarely used 4:1:1 YUV stream, some mjpegtools might not work.\n");
00164 }
00165 else if ((s->streams[0]->codec->pix_fmt != PIX_FMT_YUV420P) &&
00166 (s->streams[0]->codec->pix_fmt != PIX_FMT_YUV422P) &&
00167 (s->streams[0]->codec->pix_fmt != PIX_FMT_GRAY8) &&
00168 (s->streams[0]->codec->pix_fmt != PIX_FMT_YUV444P)) {
00169 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");
00170 return AVERROR(EIO);
00171 }
00172
00173 *first_pkt = 1;
00174 return 0;
00175 }
00176
00177 AVOutputFormat ff_yuv4mpegpipe_muxer = {
00178 "yuv4mpegpipe",
00179 NULL_IF_CONFIG_SMALL("YUV4MPEG pipe format"),
00180 "",
00181 "y4m",
00182 sizeof(int),
00183 CODEC_ID_NONE,
00184 CODEC_ID_RAWVIDEO,
00185 yuv4_write_header,
00186 yuv4_write_packet,
00187 .flags = AVFMT_RAWPICTURE,
00188 };
00189 #endif
00190
00191
00192 #define MAX_YUV4_HEADER 80
00193 #define MAX_FRAME_HEADER 80
00194
00195 static int yuv4_read_header(AVFormatContext *s, AVFormatParameters *ap)
00196 {
00197 char header[MAX_YUV4_HEADER+10];
00198 char *tokstart,*tokend,*header_end;
00199 int i;
00200 AVIOContext *pb = s->pb;
00201 int width=-1, height=-1, raten=0, rated=0, aspectn=0, aspectd=0;
00202 enum PixelFormat pix_fmt=PIX_FMT_NONE,alt_pix_fmt=PIX_FMT_NONE;
00203 enum AVChromaLocation chroma_sample_location = AVCHROMA_LOC_UNSPECIFIED;
00204 AVStream *st;
00205 struct frame_attributes *s1 = s->priv_data;
00206
00207 for (i=0; i<MAX_YUV4_HEADER; i++) {
00208 header[i] = avio_r8(pb);
00209 if (header[i] == '\n') {
00210 header[i+1] = 0x20;
00211 header[i+2] = 0;
00212 break;
00213 }
00214 }
00215 if (i == MAX_YUV4_HEADER) return -1;
00216 if (strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC))) return -1;
00217
00218 s1->interlaced_frame = 0;
00219 s1->top_field_first = 0;
00220 header_end = &header[i+1];
00221 for(tokstart = &header[strlen(Y4M_MAGIC) + 1]; tokstart < header_end; tokstart++) {
00222 if (*tokstart==0x20) continue;
00223 switch (*tokstart++) {
00224 case 'W':
00225 width = strtol(tokstart, &tokend, 10);
00226 tokstart=tokend;
00227 break;
00228 case 'H':
00229 height = strtol(tokstart, &tokend, 10);
00230 tokstart=tokend;
00231 break;
00232 case 'C':
00233 if (strncmp("420jpeg",tokstart,7)==0) {
00234 pix_fmt = PIX_FMT_YUV420P;
00235 chroma_sample_location = AVCHROMA_LOC_CENTER;
00236 } else if (strncmp("420mpeg2",tokstart,8)==0) {
00237 pix_fmt = PIX_FMT_YUV420P;
00238 chroma_sample_location = AVCHROMA_LOC_LEFT;
00239 } else if (strncmp("420paldv", tokstart, 8)==0) {
00240 pix_fmt = PIX_FMT_YUV420P;
00241 chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
00242 } else if (strncmp("411", tokstart, 3)==0)
00243 pix_fmt = PIX_FMT_YUV411P;
00244 else if (strncmp("422", tokstart, 3)==0)
00245 pix_fmt = PIX_FMT_YUV422P;
00246 else if (strncmp("444alpha", tokstart, 8)==0) {
00247 av_log(s, AV_LOG_ERROR, "Cannot handle 4:4:4:4 YUV4MPEG stream.\n");
00248 return -1;
00249 } else if (strncmp("444", tokstart, 3)==0)
00250 pix_fmt = PIX_FMT_YUV444P;
00251 else if (strncmp("mono",tokstart, 4)==0) {
00252 pix_fmt = PIX_FMT_GRAY8;
00253 } else {
00254 av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains an unknown pixel format.\n");
00255 return -1;
00256 }
00257 while(tokstart<header_end&&*tokstart!=0x20) tokstart++;
00258 break;
00259 case 'I':
00260 switch (*tokstart++){
00261 case '?':
00262 break;
00263 case 'p':
00264 s1->interlaced_frame=0;
00265 break;
00266 case 't':
00267 s1->interlaced_frame=1;
00268 s1->top_field_first=1;
00269 break;
00270 case 'b':
00271 s1->interlaced_frame=1;
00272 s1->top_field_first=0;
00273 break;
00274 case 'm':
00275 av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed interlaced and non-interlaced frames.\n");
00276 return -1;
00277 default:
00278 av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
00279 return -1;
00280 }
00281 break;
00282 case 'F':
00283 sscanf(tokstart,"%d:%d",&raten,&rated);
00284 while(tokstart<header_end&&*tokstart!=0x20) tokstart++;
00285 break;
00286 case 'A':
00287 sscanf(tokstart,"%d:%d",&aspectn,&aspectd);
00288 while(tokstart<header_end&&*tokstart!=0x20) tokstart++;
00289 break;
00290 case 'X':
00291 if (strncmp("YSCSS=",tokstart,6)==0) {
00292
00293 tokstart+=6;
00294 if (strncmp("420JPEG",tokstart,7)==0)
00295 alt_pix_fmt=PIX_FMT_YUV420P;
00296 else if (strncmp("420MPEG2",tokstart,8)==0)
00297 alt_pix_fmt=PIX_FMT_YUV420P;
00298 else if (strncmp("420PALDV",tokstart,8)==0)
00299 alt_pix_fmt=PIX_FMT_YUV420P;
00300 else if (strncmp("411",tokstart,3)==0)
00301 alt_pix_fmt=PIX_FMT_YUV411P;
00302 else if (strncmp("422",tokstart,3)==0)
00303 alt_pix_fmt=PIX_FMT_YUV422P;
00304 else if (strncmp("444",tokstart,3)==0)
00305 alt_pix_fmt=PIX_FMT_YUV444P;
00306 }
00307 while(tokstart<header_end&&*tokstart!=0x20) tokstart++;
00308 break;
00309 }
00310 }
00311
00312 if ((width == -1) || (height == -1)) {
00313 av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
00314 return -1;
00315 }
00316
00317 if (pix_fmt == PIX_FMT_NONE) {
00318 if (alt_pix_fmt == PIX_FMT_NONE)
00319 pix_fmt = PIX_FMT_YUV420P;
00320 else
00321 pix_fmt = alt_pix_fmt;
00322 }
00323
00324 if (raten <= 0 || rated <= 0) {
00325
00326 raten = 25;
00327 rated = 1;
00328 }
00329
00330 if (aspectn == 0 && aspectd == 0) {
00331
00332 aspectd = 1;
00333 }
00334
00335 st = av_new_stream(s, 0);
00336 if(!st)
00337 return AVERROR(ENOMEM);
00338 st->codec->width = width;
00339 st->codec->height = height;
00340 av_reduce(&raten, &rated, raten, rated, (1UL<<31)-1);
00341 av_set_pts_info(st, 64, rated, raten);
00342 st->codec->pix_fmt = pix_fmt;
00343 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00344 st->codec->codec_id = CODEC_ID_RAWVIDEO;
00345 st->sample_aspect_ratio= (AVRational){aspectn, aspectd};
00346 st->codec->chroma_sample_location = chroma_sample_location;
00347
00348 return 0;
00349 }
00350
00351 static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt)
00352 {
00353 int i;
00354 char header[MAX_FRAME_HEADER+1];
00355 int packet_size, width, height, ret;
00356 AVStream *st = s->streams[0];
00357 struct frame_attributes *s1 = s->priv_data;
00358
00359 for (i=0; i<MAX_FRAME_HEADER; i++) {
00360 header[i] = avio_r8(s->pb);
00361 if (header[i] == '\n') {
00362 header[i+1] = 0;
00363 break;
00364 }
00365 }
00366 if (s->pb->error)
00367 return s->pb->error;
00368 else if (s->pb->eof_reached)
00369 return AVERROR_EOF;
00370 else if (i == MAX_FRAME_HEADER)
00371 return AVERROR_INVALIDDATA;
00372
00373 if (strncmp(header, Y4M_FRAME_MAGIC, strlen(Y4M_FRAME_MAGIC)))
00374 return AVERROR_INVALIDDATA;
00375
00376 width = st->codec->width;
00377 height = st->codec->height;
00378
00379 packet_size = avpicture_get_size(st->codec->pix_fmt, width, height);
00380 if (packet_size < 0)
00381 return packet_size;
00382
00383 ret = av_get_packet(s->pb, pkt, packet_size);
00384 if (ret < 0)
00385 return ret;
00386 else if (ret != packet_size)
00387 return s->pb->eof_reached ? AVERROR_EOF : AVERROR(EIO);
00388
00389 if (s->streams[0]->codec->coded_frame) {
00390 s->streams[0]->codec->coded_frame->interlaced_frame = s1->interlaced_frame;
00391 s->streams[0]->codec->coded_frame->top_field_first = s1->top_field_first;
00392 }
00393
00394 pkt->stream_index = 0;
00395 return 0;
00396 }
00397
00398 static int yuv4_probe(AVProbeData *pd)
00399 {
00400
00401 if (strncmp(pd->buf, Y4M_MAGIC, sizeof(Y4M_MAGIC)-1)==0)
00402 return AVPROBE_SCORE_MAX;
00403 else
00404 return 0;
00405 }
00406
00407 #if CONFIG_YUV4MPEGPIPE_DEMUXER
00408 AVInputFormat ff_yuv4mpegpipe_demuxer = {
00409 "yuv4mpegpipe",
00410 NULL_IF_CONFIG_SMALL("YUV4MPEG pipe format"),
00411 sizeof(struct frame_attributes),
00412 yuv4_probe,
00413 yuv4_read_header,
00414 yuv4_read_packet,
00415 .extensions = "y4m"
00416 };
00417 #endif