X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fmodules%2Favformat%2Fconsumer_avformat.c;h=580956e2cf39206301d42f089b3747a15b77dd55;hb=64c51a40757305efd9a033024879ec08992e62a5;hp=8eaabce585d3bab573c8be28d5adfe9c139be090;hpb=681b27e7a8e217d6106096910369c213124fb28b;p=melted diff --git a/src/modules/avformat/consumer_avformat.c b/src/modules/avformat/consumer_avformat.c index 8eaabce..580956e 100644 --- a/src/modules/avformat/consumer_avformat.c +++ b/src/modules/avformat/consumer_avformat.c @@ -3,19 +3,19 @@ * 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 @@ -35,6 +35,9 @@ // avformat header files #include +#ifdef SWSCALE +#include +#endif // // This structure should be extended and made globally available in mlt @@ -189,10 +192,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 +211,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 +336,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" ) ) { @@ -489,6 +497,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" ); @@ -511,6 +520,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 { @@ -733,6 +750,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 ); @@ -802,7 +845,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 @@ -855,14 +898,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; } @@ -909,24 +953,43 @@ 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 ++ ) { - p = input->data[ 0 ] + i * input->linesize[ 0 ]; + n = ( width + 7 ) / 8; + p = output->data[ 0 ] + i * output->linesize[ 0 ]; + #ifndef __DARWIN__ p += 3; #endif - j = width; - while( j -- ) + + switch( width % 8 ) { - *p = *alpha ++; - *p += 4; + 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 ); } } } @@ -951,16 +1014,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; @@ -972,6 +1039,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 ); @@ -1000,6 +1071,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); @@ -1015,7 +1150,7 @@ static void *consumer_thread( void *arg ) // Close the output file if (!(fmt->flags & AVFMT_NOFILE)) - url_fclose(&oc->pb); + url_fclose(oc->pb); // Clean up input and output frames if ( output )