#include <framework/mlt_frame.h>
#include <framework/mlt_profile.h>
#include <framework/mlt_log.h>
+#include <framework/mlt_events.h>
// System header files
#include <stdio.h>
#define MAX_AUDIO_STREAMS (8)
#define AUDIO_ENCODE_BUFFER_SIZE (48000 * 2 * MAX_AUDIO_STREAMS)
+#define AUDIO_BUFFER_SIZE (1024 * 42)
+#define VIDEO_BUFFER_SIZE (2048 * 1024)
void avformat_lock( );
void avformat_unlock( );
this->start = consumer_start;
this->stop = consumer_stop;
this->is_stopped = consumer_is_stopped;
+
+ mlt_events_register( properties, "consumer-fatal-error", NULL );
}
// Return this
char *s = mlt_properties_get( properties, "f" );
if ( s && strcmp( s, "list" ) == 0 )
{
- fprintf( stderr, "---\nformats:\n" );
+ mlt_properties doc = mlt_properties_new();
+ mlt_properties formats = mlt_properties_new();
+ char key[20];
AVOutputFormat *format = NULL;
+
+ mlt_properties_set_data( properties, "f", formats, 0, (mlt_destructor) mlt_properties_close, NULL );
+ mlt_properties_set_data( doc, "formats", formats, 0, NULL, NULL );
while ( ( format = av_oformat_next( format ) ) )
- fprintf( stderr, " - %s\n", format->name );
- fprintf( stderr, "...\n" );
+ {
+ snprintf( key, sizeof(key), "%d", mlt_properties_count( formats ) );
+ mlt_properties_set( formats, key, format->name );
+ }
+ fprintf( stderr, "%s", mlt_properties_serialise_yaml( doc ) );
+ mlt_properties_close( doc );
error = 1;
}
s = mlt_properties_get( properties, "acodec" );
if ( s && strcmp( s, "list" ) == 0 )
{
- fprintf( stderr, "---\naudio_codecs:\n" );
+ mlt_properties doc = mlt_properties_new();
+ mlt_properties codecs = mlt_properties_new();
+ char key[20];
AVCodec *codec = NULL;
+
+ mlt_properties_set_data( properties, "acodec", codecs, 0, (mlt_destructor) mlt_properties_close, NULL );
+ mlt_properties_set_data( doc, "audio_codecs", codecs, 0, NULL, NULL );
while ( ( codec = av_codec_next( codec ) ) )
if ( codec->encode && codec->type == CODEC_TYPE_AUDIO )
- fprintf( stderr, " - %s\n", codec->name );
- fprintf( stderr, "...\n" );
+ {
+ snprintf( key, sizeof(key), "%d", mlt_properties_count( codecs ) );
+ mlt_properties_set( codecs, key, codec->name );
+ }
+ fprintf( stderr, "%s", mlt_properties_serialise_yaml( doc ) );
+ mlt_properties_close( doc );
error = 1;
}
s = mlt_properties_get( properties, "vcodec" );
if ( s && strcmp( s, "list" ) == 0 )
{
- fprintf( stderr, "---\nvideo_codecs:\n" );
+ mlt_properties doc = mlt_properties_new();
+ mlt_properties codecs = mlt_properties_new();
+ char key[20];
AVCodec *codec = NULL;
+
+ mlt_properties_set_data( properties, "vcodec", codecs, 0, (mlt_destructor) mlt_properties_close, NULL );
+ mlt_properties_set_data( doc, "video_codecs", codecs, 0, NULL, NULL );
while ( ( codec = av_codec_next( codec ) ) )
if ( codec->encode && codec->type == CODEC_TYPE_VIDEO )
- fprintf( stderr, " - %s\n", codec->name );
- fprintf( stderr, "...\n" );
+ {
+ snprintf( key, sizeof(key), "%d", mlt_properties_count( codecs ) );
+ mlt_properties_set( codecs, key, codec->name );
+ }
+ fprintf( stderr, "%s", mlt_properties_serialise_yaml( doc ) );
+ mlt_properties_close( doc );
error = 1;
}
int samples = 0;
// AVFormat audio buffer and frame size
- int audio_outbuf_size = ( 1024 * 42 );
+ int audio_outbuf_size = AUDIO_BUFFER_SIZE;
uint8_t *audio_outbuf = av_malloc( audio_outbuf_size );
int audio_input_frame_size = 0;
// AVFormat video buffer and frame count
int frame_count = 0;
- int video_outbuf_size = ( 1024 * 1024 );
+ int video_outbuf_size = VIDEO_BUFFER_SIZE;
uint8_t *video_outbuf = av_malloc( video_outbuf_size );
// Used for the frame properties
}
// Write metadata
+#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0)
+ for ( i = 0; i < mlt_properties_count( properties ); i++ )
+ {
+ char *name = mlt_properties_get_name( properties, i );
+ if ( name && !strncmp( name, "meta.attr.", 10 ) )
+ {
+ char *key = strdup( name + 10 );
+ char *markup = strrchr( key, '.' );
+ if ( markup && !strcmp( markup, ".markup") )
+ {
+ markup[0] = '\0';
+ if ( !strstr( key, ".stream." ) )
+#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(43<<8)+0)
+ av_metadata_set2( &oc->metadata, key, mlt_properties_get_value( properties, i ), 0 );
+#else
+ av_metadata_set( &oc->metadata, key, mlt_properties_get_value( properties, i ) );
+#endif
+ }
+ free( key );
+ }
+ }
+#else
char *tmp = NULL;
int metavalue;
metavalue = mlt_properties_get_int( properties, "meta.attr.track.markup");
if (metavalue != 0) oc->track = metavalue;
+#endif
oc->oformat = fmt;
snprintf( oc->filename, sizeof(oc->filename), "%s", filename );
// Get the audio samples
if ( n > 0 )
+ {
sample_fifo_fetch( fifo, audio_buf_1, n );
+ }
+ else if ( audio_codec_id == CODEC_ID_VORBIS && terminated )
+ {
+ // This prevents an infinite loop when some versions of vorbis do not
+ // increment pts when encoding silence.
+ audio_pts = video_pts;
+ break;
+ }
else
+ {
memset( audio_buf_1, 0, AUDIO_ENCODE_BUFFER_SIZE );
+ }
samples = n / channels;
// For each output stream
if ( pkt.size > 0 )
{
if ( av_interleaved_write_frame( oc, &pkt ) )
- mlt_log_error( MLT_CONSUMER_SERVICE( this ), "error writing audio frame %d\n", frames - 1 );
+ {
+ mlt_log_fatal( MLT_CONSUMER_SERVICE( this ), "error writing audio frame\n" );
+ mlt_events_fire( properties, "consumer-fatal-error", NULL );
+ goto on_fatal_error;
+ }
}
mlt_log_debug( MLT_CONSUMER_SERVICE( this ), " frame_size %d\n", codec->frame_size );
// Write video
if ( mlt_deque_count( queue ) )
{
- int out_size, ret;
+ int out_size, ret = 0;
AVCodecContext *c;
frame = mlt_deque_pop_front( queue );
if ( mlt_properties_get_int( frame_properties, "rendered" ) )
{
int i = 0;
- int j = 0;
uint8_t *p;
uint8_t *q;
for ( i = 0; i < height; i ++ )
{
p = input->data[ 0 ] + i * input->linesize[ 0 ];
- j = width;
- while( j -- )
- {
- *p ++ = *q ++;
- *p ++ = *q ++;
- }
+ memcpy( p, q, width * 2 );
+ q += width * 2;
}
// Do the colour space conversion
}
}
frame_count++;
+ if ( ret )
+ {
+ mlt_log_fatal( MLT_CONSUMER_SERVICE( this ), "error writing video frame\n" );
+ mlt_events_fire( properties, "consumer-fatal-error", NULL );
+ goto on_fatal_error;
+ }
mlt_frame_close( frame );
}
else
pkt.data = audio_outbuf;
if ( av_interleaved_write_frame( oc, &pkt ) != 0 )
{
- mlt_log_error( MLT_CONSUMER_SERVICE( this ), "%s: error writing flushed audio frame\n", __FILE__ );
- break;
+ mlt_log_fatal( MLT_CONSUMER_SERVICE( this ), "error writing flushed audio frame\n" );
+ mlt_events_fire( properties, "consumer-fatal-error", NULL );
+ goto on_fatal_error;
}
}
// write the compressed frame in the media file
if ( av_interleaved_write_frame( oc, &pkt ) != 0 )
{
- mlt_log_error( MLT_CONSUMER_SERVICE(this), "error writing flushed video frame\n" );
- break;
+ mlt_log_fatal( MLT_CONSUMER_SERVICE(this), "error writing flushed video frame\n" );
+ mlt_events_fire( properties, "consumer-fatal-error", NULL );
+ goto on_fatal_error;
}
// Dual pass logging
if ( mlt_properties_get_data( properties, "_logfile", NULL ) && c->stats_out )
}
}
+on_fatal_error:
+
// Write the trailer, if any
av_write_trailer( oc );