X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fmodules%2Favformat%2Fconsumer_avformat.c;h=5a1ab27201c5faf0709a8cdee2eae8f2e7f9f9ca;hb=d33f444d4ef4c7bc4074d07a49eca0ab7d108394;hp=81e6906594fd617427123195d33f7ab7440c514b;hpb=66509fd3206d09ae512886560660ac88d4b9c128;p=melted diff --git a/src/modules/avformat/consumer_avformat.c b/src/modules/avformat/consumer_avformat.c index 81e6906..5a1ab27 100644 --- a/src/modules/avformat/consumer_avformat.c +++ b/src/modules/avformat/consumer_avformat.c @@ -3,25 +3,23 @@ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// Local header files -#include "consumer_avformat.h" - // mlt Header files +#include #include // System header files @@ -35,6 +33,9 @@ // avformat header files #include +#ifdef SWSCALE +#include +#endif // // This structure should be extended and made globally available in mlt @@ -133,10 +134,10 @@ static void consumer_close( mlt_consumer this ); /** Initialise the dv consumer. */ -mlt_consumer consumer_avformat_init( char *arg ) +mlt_consumer consumer_avformat_init( mlt_profile profile, char *arg ) { // Allocate the consumer - mlt_consumer this = mlt_consumer_new( ); + mlt_consumer this = mlt_consumer_new( profile ); // If memory allocated and initialises without error if ( this != NULL ) @@ -189,10 +190,10 @@ mlt_consumer consumer_avformat_init( char *arg ) mlt_properties_set_int( properties, "video_rc_buffer_size", 0 ); mlt_properties_set_double( properties, "video_rc_buffer_aggressivity", 1.0 ); mlt_properties_set_double( properties, "video_rc_initial_cplx", 0 ); - mlt_properties_set_double( properties, "video_i_qfactor", 1.25 ); + mlt_properties_set_double( properties, "video_i_qfactor", -0.8 ); mlt_properties_set_double( properties, "video_b_qfactor", 1.25 ); - mlt_properties_set_double( properties, "video_i_qoffset", -0.8 ); - mlt_properties_set_double( properties, "video_b_qoffset", 0 ); + mlt_properties_set_double( properties, "video_i_qoffset", 0 ); + mlt_properties_set_double( properties, "video_b_qoffset", 1.25 ); mlt_properties_set_int( properties, "video_intra_quant_bias", FF_DEFAULT_QUANT_BIAS ); mlt_properties_set_int( properties, "video_inter_quant_bias", FF_DEFAULT_QUANT_BIAS ); mlt_properties_set_int( properties, "dct_algo", 0 ); @@ -208,6 +209,8 @@ mlt_consumer consumer_avformat_init( char *arg ) mlt_properties_set_int( properties, "coder", 0 ); mlt_properties_set_int( properties, "context", 0 ); mlt_properties_set_int( properties, "predictor", 0 ); + mlt_properties_set_int( properties, "ildct", 0 ); + mlt_properties_set_int( properties, "ilme", 0 ); // Ensure termination at end of the stream mlt_properties_set_int( properties, "terminate_on_pause", 1 ); @@ -331,6 +334,9 @@ static AVStream *add_audio_stream( mlt_consumer this, AVFormatContext *oc, int c c->sample_rate = mlt_properties_get_int( properties, "frequency" ); c->channels = mlt_properties_get_int( properties, "channels" ); + if (oc->oformat->flags & AVFMT_GLOBALHEADER) + c->flags |= CODEC_FLAG_GLOBAL_HEADER; + // Allow the user to override the audio fourcc if ( mlt_properties_get( properties, "afourcc" ) ) { @@ -418,6 +424,8 @@ static AVStream *add_video_stream( mlt_consumer this, AVFormatContext *oc, int c if ( st != NULL ) { + char *pix_fmt = mlt_properties_get( properties, "pix_fmt" ); + double ar = mlt_properties_get_double( properties, "display_ratio" ); AVCodecContext *c = st->codec; c->codec_id = codec_id; c->codec_type = CODEC_TYPE_VIDEO; @@ -430,7 +438,7 @@ static AVStream *add_video_stream( mlt_consumer this, AVFormatContext *oc, int c c->time_base.num = mlt_properties_get_int( properties, "frame_rate_den" ); c->time_base.den = mlt_properties_get_int( properties, "frame_rate_num" ); c->gop_size = mlt_properties_get_int( properties, "gop_size" ); - c->pix_fmt = PIX_FMT_YUV420P; + c->pix_fmt = pix_fmt ? avcodec_get_pix_fmt( pix_fmt ) : PIX_FMT_YUV420P; if ( mlt_properties_get_int( properties, "b_frames" ) ) { @@ -440,8 +448,7 @@ static AVStream *add_video_stream( mlt_consumer this, AVFormatContext *oc, int c } c->mb_decision = mlt_properties_get_int( properties, "mb_decision" ); - c->sample_aspect_ratio.den = mlt_properties_get_double( properties, "aspect_ratio_den" ); - c->sample_aspect_ratio.num = mlt_properties_get_double( properties, "aspect_ratio_num" ); + c->sample_aspect_ratio = av_d2q( ar * c->height / c->width , 255); c->mb_cmp = mlt_properties_get_int( properties, "mb_cmp" ); c->ildct_cmp = mlt_properties_get_int( properties, "ildct_cmp" ); c->me_sub_cmp = mlt_properties_get_int( properties, "sub_cmp" ); @@ -488,6 +495,7 @@ static AVStream *add_video_stream( mlt_consumer this, AVFormatContext *oc, int c c->rc_max_rate = mlt_properties_get_int( properties, "video_rc_max_rate" ); c->rc_min_rate = mlt_properties_get_int( properties, "video_rc_min_rate" ); c->rc_buffer_size = mlt_properties_get_int( properties, "video_rc_buffer_size" ); + c->rc_initial_buffer_occupancy = c->rc_buffer_size*3/4; c->rc_buffer_aggressivity= mlt_properties_get_double( properties, "video_rc_buffer_aggressivity" ); c->rc_initial_cplx= mlt_properties_get_double( properties, "video_rc_initial_cplx" ); c->i_quant_factor = mlt_properties_get_double( properties, "video_i_qfactor" ); @@ -510,6 +518,14 @@ static AVStream *add_video_stream( mlt_consumer this, AVFormatContext *oc, int c c->context_model= mlt_properties_get_int( properties, "context" ); c->prediction_method= mlt_properties_get_int( properties, "predictor" ); c->me_method = mlt_properties_get_int( properties, "me_method" ); + if ( mlt_properties_get_int( properties, "progressive" ) == 0 && + mlt_properties_get_int( properties, "deinterlace" ) == 0 ) + { + if ( mlt_properties_get_int( properties, "ildct" ) ) + c->flags |= CODEC_FLAG_INTERLACED_DCT; + if ( mlt_properties_get_int( properties, "ilme" ) ) + c->flags |= CODEC_FLAG_INTERLACED_ME; + } } else { @@ -605,7 +621,7 @@ static void *consumer_thread( void *arg ) struct timeval ante; // Get the frame rate - int fps = mlt_properties_get_double( properties, "fps" ); + double fps = mlt_properties_get_double( properties, "fps" ); // Get width and height int width = mlt_properties_get_int( properties, "width" ); @@ -732,6 +748,32 @@ static void *consumer_thread( void *arg ) } // Update the output context + + // Write metadata + char *tmp = NULL; + int metavalue; + + tmp = mlt_properties_get( properties, "meta.attr.title.markup"); + if (tmp != NULL) snprintf( oc->title, sizeof(oc->title), "%s", tmp ); + + tmp = mlt_properties_get( properties, "meta.attr.comment.markup"); + if (tmp != NULL) snprintf( oc->comment, sizeof(oc->comment), "%s", tmp ); + + tmp = mlt_properties_get( properties, "meta.attr.author.markup"); + if (tmp != NULL) snprintf( oc->author, sizeof(oc->author), "%s", tmp ); + + tmp = mlt_properties_get( properties, "meta.attr.copyright.markup"); + if (tmp != NULL) snprintf( oc->copyright, sizeof(oc->copyright), "%s", tmp ); + + tmp = mlt_properties_get( properties, "meta.attr.album.markup"); + if (tmp != NULL) snprintf( oc->album, sizeof(oc->album), "%s", tmp ); + + metavalue = mlt_properties_get_int( properties, "meta.attr.year.markup"); + if (metavalue != 0) oc->year = metavalue; + + metavalue = mlt_properties_get_int( properties, "meta.attr.track.markup"); + if (metavalue != 0) oc->track = metavalue; + oc->oformat = fmt; snprintf( oc->filename, sizeof(oc->filename), "%s", filename ); @@ -801,7 +843,7 @@ static void *consumer_thread( void *arg ) // Get audio and append to the fifo if ( !terminated && audio_st ) { - samples = mlt_sample_calculator( fps, frequency, count ); + samples = mlt_sample_calculator( fps, frequency, count ++ ); mlt_frame_get_audio( frame, &pcm, &aud_fmt, &frequency, &channels, &samples ); // Create the fifo if we don't have one @@ -854,14 +896,15 @@ static void *consumer_thread( void *arg ) pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, buffer ); // Write the compressed frame in the media file - if ( c->coded_frame ) + if ( c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE ) pkt.pts = av_rescale_q( c->coded_frame->pts, c->time_base, audio_st->time_base ); pkt.flags |= PKT_FLAG_KEY; pkt.stream_index= audio_st->index; pkt.data= audio_outbuf; - if ( av_interleaved_write_frame( oc, &pkt ) != 0) - fprintf(stderr, "Error while writing audio frame\n"); + if ( pkt.size ) + if ( av_interleaved_write_frame( oc, &pkt ) != 0) + fprintf(stderr, "Error while writing audio frame\n"); audio_pts += c->frame_size; } @@ -891,17 +934,11 @@ static void *consumer_thread( void *arg ) mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); - // This will cause some fx to go awry.... - if ( mlt_properties_get_int( properties, "transcode" ) ) - { - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "normalised_width", img_height * 4.0 / 3.0 ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "normalised_height", img_height ); - } - mlt_frame_get_image( frame, &image, &img_fmt, &img_width, &img_height, 0 ); q = image; + // Convert the mlt frame to an AVPicture for ( i = 0; i < height; i ++ ) { p = input->data[ 0 ] + i * input->linesize[ 0 ]; @@ -913,7 +950,47 @@ static void *consumer_thread( void *arg ) } } + // Do the colour space conversion +#ifdef SWSCALE + struct SwsContext *context = sws_getContext( width, height, PIX_FMT_YUV422, + width, height, video_st->codec->pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL); + sws_scale( context, input->data, input->linesize, 0, height, + output->data, output->linesize); + sws_freeContext( context ); +#else img_convert( ( AVPicture * )output, video_st->codec->pix_fmt, ( AVPicture * )input, PIX_FMT_YUV422, width, height ); +#endif + + // Apply the alpha if applicable + if ( video_st->codec->pix_fmt == PIX_FMT_RGBA32 ) + { + uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); + register int n; + + for ( i = 0; i < height; i ++ ) + { + n = ( width + 7 ) / 8; + p = output->data[ 0 ] + i * output->linesize[ 0 ]; + + #ifndef __DARWIN__ + p += 3; + #endif + + switch( width % 8 ) + { + case 0: do { *p = *alpha++; p += 4; + case 7: *p = *alpha++; p += 4; + case 6: *p = *alpha++; p += 4; + case 5: *p = *alpha++; p += 4; + case 4: *p = *alpha++; p += 4; + case 3: *p = *alpha++; p += 4; + case 2: *p = *alpha++; p += 4; + case 1: *p = *alpha++; p += 4; + } + while( --n ); + } + } + } } if (oc->oformat->flags & AVFMT_RAWPICTURE) @@ -935,16 +1012,20 @@ static void *consumer_thread( void *arg ) // Set the quality output->quality = video_st->quality; + // Set frame interlace hints + output->interlaced_frame = !mlt_properties_get_int( frame_properties, "progressive" ); + output->top_field_first = mlt_properties_get_int( frame_properties, "top_field_first" ); + // Encode the image out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, output ); // If zero size, it means the image was buffered - if (out_size != 0) + if (out_size > 0) { AVPacket pkt; av_init_packet( &pkt ); - if ( c->coded_frame ) + if ( c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE ) pkt.pts= av_rescale_q( c->coded_frame->pts, c->time_base, video_st->time_base ); if( c->coded_frame && c->coded_frame->key_frame ) pkt.flags |= PKT_FLAG_KEY; @@ -956,6 +1037,10 @@ static void *consumer_thread( void *arg ) ret = av_interleaved_write_frame(oc, &pkt); video_pts += c->frame_size; } + else + { + fprintf( stderr, "Error with video encode\n" ); + } } frame_count++; mlt_frame_close( frame ); @@ -984,6 +1069,70 @@ static void *consumer_thread( void *arg ) } } +#ifdef FLUSH + if ( ! real_time_output ) + { + // Flush audio fifo + if ( audio_st && audio_st->codec->frame_size > 1 ) for (;;) + { + AVCodecContext *c = audio_st->codec; + AVPacket pkt; + av_init_packet( &pkt ); + pkt.size = 0; + + if ( /*( c->capabilities & CODEC_CAP_SMALL_LAST_FRAME ) &&*/ + ( channels * audio_input_frame_size < sample_fifo_used( fifo ) ) ) + { + sample_fifo_fetch( fifo, buffer, channels * audio_input_frame_size ); + pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, buffer ); + } + if ( pkt.size <= 0 ) + pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, NULL ); + if ( pkt.size <= 0 ) + break; + + // Write the compressed frame in the media file + if ( c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE ) + pkt.pts = av_rescale_q( c->coded_frame->pts, c->time_base, audio_st->time_base ); + pkt.flags |= PKT_FLAG_KEY; + pkt.stream_index = audio_st->index; + pkt.data = audio_outbuf; + if ( av_interleaved_write_frame( oc, &pkt ) != 0 ) + { + fprintf(stderr, "Error while writing flushed audio frame\n"); + break; + } + } + + // Flush video + if ( video_st && !( oc->oformat->flags & AVFMT_RAWPICTURE ) ) for (;;) + { + AVCodecContext *c = video_st->codec; + AVPacket pkt; + av_init_packet( &pkt ); + + // Encode the image + pkt.size = avcodec_encode_video( c, video_outbuf, video_outbuf_size, NULL ); + if ( pkt.size <= 0 ) + break; + + if ( c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE ) + pkt.pts= av_rescale_q( c->coded_frame->pts, c->time_base, video_st->time_base ); + if( c->coded_frame && c->coded_frame->key_frame ) + pkt.flags |= PKT_FLAG_KEY; + pkt.stream_index = video_st->index; + pkt.data = video_outbuf; + + // write the compressed frame in the media file + if ( av_interleaved_write_frame( oc, &pkt ) != 0 ) + { + fprintf(stderr, "Error while writing flushed video frame\n"); + break; + } + } + } +#endif + // close each codec if (video_st) close_video(oc, video_st); @@ -999,7 +1148,11 @@ static void *consumer_thread( void *arg ) // Close the output file if (!(fmt->flags & AVFMT_NOFILE)) +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(0<<8)+0) + url_fclose(oc->pb); +#else url_fclose(&oc->pb); +#endif // Clean up input and output frames if ( output )