@ -30,6 +30,7 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf)
int width , height ;
int raten , rated , aspectn , aspectd , n ;
char inter ;
char * colorspace = " " ;
st = s - > streams [ 0 ] ;
width = st - > codec . width ;
@ -40,11 +41,28 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf)
aspectn = st - > codec . sample_aspect_ratio . num ;
aspectd = st - > codec . sample_aspect_ratio . den ;
if ( aspectn = = 0 & & aspectd = = 1 ) aspectd = 0 ; // 0:0 means unknown
inter = ' p ' ; /* progressive is the default */
if ( st - > codec . coded_frame & & st - > codec . coded_frame - > interlaced_frame ) {
inter = st - > codec . coded_frame - > top_field_first ? ' t ' : ' b ' ;
}
switch ( st - > codec . pix_fmt ) {
case PIX_FMT_YUV411P :
colorspace = " C411 XYSCSS=411 " ;
break ;
case PIX_FMT_YUV420P :
colorspace = ( st - > codec . codec_id = = CODEC_ID_DVVIDEO ) ? " C420paldv XYSCSS=420PALDV " : " C420mpeg2 XYSCSS=420MPEG2 " ;
break ;
case PIX_FMT_YUV422P :
colorspace = " C422 XYSCSS=422 " ;
break ;
case PIX_FMT_YUV444P :
colorspace = " C444 XYSCSS=444 " ;
break ;
}
/* construct stream header, if this is the first frame */
n = snprintf ( buf , Y4M_LINE_MAX , " %s W%d H%d F%d:%d I%c A%d:%d%s \n " ,
Y4M_MAGIC ,
@ -53,7 +71,7 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf)
raten , rated ,
inter ,
aspectn , aspectd ,
( st - > codec . pix_fmt = = PIX_FMT_YUV411P ) ? " C411 XYSCSS=411 " : " C420mpeg2 XYSCSS=420MPEG2 " ) ;
colorspace ) ;
return n ;
}
@ -64,7 +82,7 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
ByteIOContext * pb = & s - > pb ;
AVPicture * picture ;
int * first_pkt = s - > priv_data ;
int width , height ;
int width , height , h_chroma_shift , v_chroma_shift ;
int i , m ;
char buf2 [ Y4M_LINE_MAX + 1 ] ;
char buf1 [ 20 ] ;
@ -97,8 +115,11 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
ptr + = picture - > linesize [ 0 ] ;
}
height > > = 1 ;
width > > = 1 ;
// Adjust for smaller Cb and Cr planes
avcodec_get_chroma_sub_sample ( st - > codec . pix_fmt , & h_chroma_shift , & v_chroma_shift ) ;
width > > = h_chroma_shift ;
height > > = v_chroma_shift ;
ptr1 = picture - > data [ 1 ] ;
ptr2 = picture - > data [ 2 ] ;
for ( i = 0 ; i < height ; i + + ) { /* Cb */
@ -121,10 +142,12 @@ static int yuv4_write_header(AVFormatContext *s)
return AVERROR_IO ;
if ( s - > streams [ 0 ] - > codec . pix_fmt = = PIX_FMT_YUV411P ) {
av_log ( s , AV_LOG_ERROR , " Warning: generating non-standar d 4:1:1 YUV stream, some mjpegtools might not work. \n " ) ;
av_log ( s , AV_LOG_ERROR , " Warning: generating rarely use d 4:1:1 YUV stream, some mjpegtools might not work. \n " ) ;
}
else if ( s - > streams [ 0 ] - > codec . pix_fmt ! = PIX_FMT_YUV420P ) {
av_log ( s , AV_LOG_ERROR , " ERROR: yuv4mpeg only handles 4:2:0, 4:1:1 YUV data. Use -pix_fmt to select one. \n " ) ;
else if ( ( s - > streams [ 0 ] - > codec . pix_fmt ! = PIX_FMT_YUV420P ) & &
( s - > streams [ 0 ] - > codec . pix_fmt ! = PIX_FMT_YUV422P ) & &
( s - > streams [ 0 ] - > codec . pix_fmt ! = PIX_FMT_YUV444P ) ) {
av_log ( s , AV_LOG_ERROR , " ERROR: yuv4mpeg only handles 4:4:4, 4:2:2, 4:2:0 and 4:1:1 planar YUV data. Use -pix_fmt to select one. \n " ) ;
return AVERROR_IO ;
}
@ -154,29 +177,142 @@ AVOutputFormat yuv4mpegpipe_oformat = {
/* Header size increased to allow room for optional flags */
# define MAX_YUV4_HEADER 80
# define MAX_FRAME_HEADER 1 0
# define MAX_FRAME_HEADER 8 0
static int yuv4_read_header ( AVFormatContext * s , AVFormatParameters * ap )
{
char header [ MAX_YUV4_HEADER + 1 ] ;
char header [ MAX_YUV4_HEADER + 10 ] ; // Include headroom for the longest option
char * tokstart , * tokend , * header_end ;
int i ;
ByteIOContext * pb = & s - > pb ;
int width , height , raten , rated , aspectn , aspectd ;
char lacing ;
int width = - 1 , height = - 1 , raten = 0 , rated = 0 , aspectn = 0 , aspectd = 0 , interlaced_frame = 0 , top_field_first = 0 ;
enum PixelFormat pix_fmt = PIX_FMT_NB , alt_pix_fmt = PIX_FMT_NB ;
AVStream * st ;
for ( i = 0 ; i < MAX_YUV4_HEADER ; i + + ) {
header [ i ] = get_byte ( pb ) ;
if ( header [ i ] = = ' \n ' ) {
header [ i + 1 ] = 0 ;
header [ i + 1 ] = 0x20 ; // Add a space after last option. Makes parsing "444" vs "444alpha" easier.
header [ i + 2 ] = 0 ;
break ;
}
}
if ( i = = MAX_YUV4_HEADER ) return - 1 ;
if ( strncmp ( header , Y4M_MAGIC , strlen ( Y4M_MAGIC ) ) ) return - 1 ;
sscanf ( header + strlen ( Y4M_MAGIC ) , " W%d H%d F%d:%d I%c A%d:%d " ,
& width , & height , & raten , & rated , & lacing , & aspectn , & aspectd ) ;
header_end = & header [ i + 1 ] ; // Include space
for ( tokstart = & header [ strlen ( Y4M_MAGIC ) + 1 ] ; tokstart < header_end ; tokstart + + ) {
if ( * tokstart = = 0x20 ) continue ;
switch ( * tokstart + + ) {
case ' W ' : // Width. Required.
width = strtol ( tokstart , & tokend , 10 ) ;
tokstart = tokend ;
break ;
case ' H ' : // Height. Required.
height = strtol ( tokstart , & tokend , 10 ) ;
tokstart = tokend ;
break ;
case ' C ' : // Color space
if ( strncmp ( " 420jpeg " , tokstart , 7 ) = = 0 )
pix_fmt = PIX_FMT_YUV420P ;
else if ( strncmp ( " 420mpeg2 " , tokstart , 8 ) = = 0 )
pix_fmt = PIX_FMT_YUV420P ;
else if ( strncmp ( " 420paldv " , tokstart , 8 ) = = 0 )
pix_fmt = PIX_FMT_YUV420P ;
else if ( strncmp ( " 411 " , tokstart , 3 ) = = 0 )
pix_fmt = PIX_FMT_YUV411P ;
else if ( strncmp ( " 422 " , tokstart , 3 ) = = 0 )
pix_fmt = PIX_FMT_YUV422P ;
else if ( strncmp ( " 444alpha " , tokstart , 8 ) = = 0 ) {
av_log ( s , AV_LOG_ERROR , " Cannot handle 4:4:4:4 YUV4MPEG stream. \n " ) ;
return - 1 ;
} else if ( strncmp ( " 444 " , tokstart , 3 ) = = 0 )
pix_fmt = PIX_FMT_YUV444P ;
else if ( strncmp ( " mono " , tokstart , 4 ) = = 0 ) {
av_log ( s , AV_LOG_ERROR , " Cannot handle luma only YUV4MPEG stream. \n " ) ;
return - 1 ;
} else {
av_log ( s , AV_LOG_ERROR , " YUV4MPEG stream contains an unknown pixel format. \n " ) ;
return - 1 ;
}
while ( tokstart < header_end & & * tokstart ! = 0x20 ) tokstart + + ;
break ;
case ' I ' : // Interlace type
switch ( * tokstart + + ) {
case ' ? ' :
break ;
case ' p ' :
interlaced_frame = 0 ;
break ;
case ' t ' :
interlaced_frame = 1 ;
top_field_first = 1 ;
break ;
case ' b ' :
interlaced_frame = 1 ;
top_field_first = 0 ;
break ;
case ' m ' :
av_log ( s , AV_LOG_ERROR , " YUV4MPEG stream contains mixed interlaced and non-interlaced frames. \n " ) ;
return - 1 ;
default :
av_log ( s , AV_LOG_ERROR , " YUV4MPEG has invalid header. \n " ) ;
return - 1 ;
}
break ;
case ' F ' : // Frame rate
sscanf ( tokstart , " %d:%d " , & raten , & rated ) ; // 0:0 if unknown
while ( tokstart < header_end & & * tokstart ! = 0x20 ) tokstart + + ;
break ;
case ' A ' : // Pixel aspect
sscanf ( tokstart , " %d:%d " , & aspectn , & aspectd ) ; // 0:0 if unknown
while ( tokstart < header_end & & * tokstart ! = 0x20 ) tokstart + + ;
break ;
case ' X ' : // Vendor extensions
if ( strncmp ( " YSCSS= " , tokstart , 6 ) = = 0 ) {
// Older nonstandard pixel format representation
tokstart + = 6 ;
if ( strncmp ( " 420JPEG " , tokstart , 7 ) = = 0 )
alt_pix_fmt = PIX_FMT_YUV420P ;
else if ( strncmp ( " 420MPEG2 " , tokstart , 8 ) = = 0 )
alt_pix_fmt = PIX_FMT_YUV420P ;
else if ( strncmp ( " 420PALDV " , tokstart , 8 ) = = 0 )
alt_pix_fmt = PIX_FMT_YUV420P ;
else if ( strncmp ( " 411 " , tokstart , 3 ) = = 0 )
alt_pix_fmt = PIX_FMT_YUV411P ;
else if ( strncmp ( " 422 " , tokstart , 3 ) = = 0 )
alt_pix_fmt = PIX_FMT_YUV422P ;
else if ( strncmp ( " 444 " , tokstart , 3 ) = = 0 )
alt_pix_fmt = PIX_FMT_YUV444P ;
}
while ( tokstart < header_end & & * tokstart ! = 0x20 ) tokstart + + ;
break ;
}
}
if ( ( width = = - 1 ) | | ( height = = - 1 ) ) {
av_log ( s , AV_LOG_ERROR , " YUV4MPEG has invalid header. \n " ) ;
return - 1 ;
}
if ( pix_fmt = = PIX_FMT_NB ) {
if ( alt_pix_fmt = = PIX_FMT_NB )
pix_fmt = PIX_FMT_YUV420P ;
else
pix_fmt = alt_pix_fmt ;
}
if ( raten = = 0 & & rated = = 0 ) {
// Frame rate unknown
raten = 25 ;
rated = 1 ;
}
if ( aspectn = = 0 & & aspectd = = 0 ) {
// Pixel aspect unknown
aspectd = 1 ;
}
st = av_new_stream ( s , 0 ) ;
st = s - > streams [ 0 ] ;
st - > codec . width = width ;
@ -184,7 +320,7 @@ static int yuv4_read_header(AVFormatContext *s, AVFormatParameters *ap)
av_reduce ( & raten , & rated , raten , rated , ( 1UL < < 31 ) - 1 ) ;
st - > codec . frame_rate = raten ;
st - > codec . frame_rate_base = rated ;
st - > codec . pix_fmt = PIX_FMT_YUV420P ;
st - > codec . pix_fmt = pix_fmt ;
st - > codec . codec_type = CODEC_TYPE_VIDEO ;
st - > codec . codec_id = CODEC_ID_RAWVIDEO ;
st - > codec . sample_aspect_ratio = ( AVRational ) { aspectn , aspectd } ;