@ -44,6 +44,9 @@ typedef struct APNGMuxContext {
AVRational prev_delay ;
int framerate_warned ;
uint8_t * extra_data ;
int extra_data_size ;
} APNGMuxContext ;
static uint8_t * apng_find_chunk ( uint32_t tag , uint8_t * buf , size_t length )
@ -101,15 +104,27 @@ static int apng_write_header(AVFormatContext *format_context)
return 0 ;
}
static void flush_packet ( AVFormatContext * format_context , AVPacket * packet )
static int flush_packet ( AVFormatContext * format_context , AVPacket * packet )
{
APNGMuxContext * apng = format_context - > priv_data ;
AVIOContext * io_context = format_context - > pb ;
AVStream * codec_stream = format_context - > streams [ 0 ] ;
AVCodecParameters * codec_par = codec_stream - > codecpar ;
uint8_t * side_data = NULL ;
int side_data_size = 0 ;
av_assert0 ( apng - > prev_packet ) ;
side_data = av_packet_get_side_data ( apng - > prev_packet , AV_PKT_DATA_NEW_EXTRADATA , & side_data_size ) ;
if ( side_data_size ) {
av_freep ( & apng - > extra_data ) ;
apng - > extra_data = av_mallocz ( side_data_size + AV_INPUT_BUFFER_PADDING_SIZE ) ;
if ( ! apng - > extra_data )
return AVERROR ( ENOMEM ) ;
apng - > extra_data_size = side_data_size ;
memcpy ( apng - > extra_data , side_data , apng - > extra_data_size ) ;
}
if ( apng - > frame_number = = 0 & & ! packet ) {
uint8_t * existing_acTL_chunk ;
uint8_t * existing_fcTL_chunk ;
@ -117,13 +132,13 @@ static void flush_packet(AVFormatContext *format_context, AVPacket *packet)
av_log ( format_context , AV_LOG_INFO , " Only a single frame so saving as a normal PNG. \n " ) ;
// Write normal PNG headers without acTL chunk
existing_acTL_chunk = apng_find_chunk ( MKBETAG ( ' a ' , ' c ' , ' T ' , ' L ' ) , codec_par - > extradata , codec_par - > extradata_size ) ;
existing_acTL_chunk = apng_find_chunk ( MKBETAG ( ' a ' , ' c ' , ' T ' , ' L ' ) , apng - > extra_ data , apng - > extra_ data_size ) ;
if ( existing_acTL_chunk ) {
uint8_t * chunk_after_acTL = existing_acTL_chunk + AV_RB32 ( existing_acTL_chunk ) + 12 ;
avio_write ( io_context , codec_par - > extradata , existing_acTL_chunk - codec_par - > extradata ) ;
avio_write ( io_context , chunk_after_acTL , codec_par - > extradata + codec_par - > extradata_size - chunk_after_acTL ) ;
avio_write ( io_context , apng - > extra_ data , existing_acTL_chunk - apng - > extra_ data ) ;
avio_write ( io_context , chunk_after_acTL , apng - > extra_ data + apng - > extra_ data_size - chunk_after_acTL ) ;
} else {
avio_write ( io_context , codec_par - > extradata , codec_par - > extradata_size ) ;
avio_write ( io_context , apng - > extra_ data , apng - > extra_ data_size ) ;
}
// Write frame data without fcTL chunk
@ -142,9 +157,9 @@ static void flush_packet(AVFormatContext *format_context, AVPacket *packet)
uint8_t * existing_acTL_chunk ;
// Write normal PNG headers
avio_write ( io_context , codec_par - > extradata , codec_par - > extradata_size ) ;
avio_write ( io_context , apng - > extra_ data , apng - > extra_ data_size ) ;
existing_acTL_chunk = apng_find_chunk ( MKBETAG ( ' a ' , ' c ' , ' T ' , ' L ' ) , codec_par - > extradata , codec_par - > extradata_size ) ;
existing_acTL_chunk = apng_find_chunk ( MKBETAG ( ' a ' , ' c ' , ' T ' , ' L ' ) , apng - > extra_ data , apng - > extra_ data_size ) ;
if ( ! existing_acTL_chunk ) {
uint8_t buf [ 8 ] ;
// Write animation control header
@ -195,11 +210,13 @@ static void flush_packet(AVFormatContext *format_context, AVPacket *packet)
av_packet_unref ( apng - > prev_packet ) ;
if ( packet )
av_copy_packet ( apng - > prev_packet , packet ) ;
return 0 ;
}
static int apng_write_packet ( AVFormatContext * format_context , AVPacket * packet )
{
APNGMuxContext * apng = format_context - > priv_data ;
int ret ;
if ( ! apng - > prev_packet ) {
apng - > prev_packet = av_malloc ( sizeof ( * apng - > prev_packet ) ) ;
@ -208,7 +225,9 @@ static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
av_copy_packet ( apng - > prev_packet , packet ) ;
} else {
flush_packet ( format_context , packet ) ;
ret = flush_packet ( format_context , packet ) ;
if ( ret < 0 )
return ret ;
}
return 0 ;
@ -219,10 +238,13 @@ static int apng_write_trailer(AVFormatContext *format_context)
APNGMuxContext * apng = format_context - > priv_data ;
AVIOContext * io_context = format_context - > pb ;
uint8_t buf [ 8 ] ;
int ret ;
if ( apng - > prev_packet ) {
flush_packet ( format_context , NULL ) ;
ret = flush_packet ( format_context , NULL ) ;
av_freep ( & apng - > prev_packet ) ;
if ( ret < 0 )
return ret ;
}
apng_write_chunk ( io_context , MKBETAG ( ' I ' , ' E ' , ' N ' , ' D ' ) , NULL , 0 ) ;
@ -235,6 +257,9 @@ static int apng_write_trailer(AVFormatContext *format_context)
apng_write_chunk ( io_context , MKBETAG ( ' a ' , ' c ' , ' T ' , ' L ' ) , buf , 8 ) ;
}
av_freep ( & apng - > extra_data ) ;
apng - > extra_data = 0 ;
return 0 ;
}