@@ -75,7 +75,7 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6
7575FFmpegWriter::FFmpegWriter (const std::string& path) :
7676 path(path), oc(NULL ), audio_st(NULL ), video_st(NULL ), samples(NULL ),
7777 audio_outbuf(NULL ), audio_outbuf_size(0 ), audio_input_frame_size(0 ), audio_input_position(0 ),
78- initial_audio_input_frame_size(0 ), img_convert_ctx(NULL ), num_of_rescalers(1 ),
78+ initial_audio_input_frame_size(0 ), img_convert_ctx(NULL ), cache_size( 1 ), num_of_rescalers(1 ),
7979 rescaler_position(0 ), video_codec_ctx(NULL ), audio_codec_ctx(NULL ), is_writing(false ), video_timestamp(0 ), audio_timestamp(0 ),
8080 original_sample_rate(0 ), original_channels(0 ), avr(NULL ), avr_planar(NULL ), is_open(false ), prepare_streams(false ),
8181 write_header(false ), write_trailer(false ), audio_encoder_buffer_size(0 ), audio_encoder_buffer(NULL ) {
@@ -679,50 +679,118 @@ void FFmpegWriter::WriteFrame(std::shared_ptr<openshot::Frame> frame) {
679679 if (!is_open)
680680 throw WriterClosed (" The FFmpegWriter is closed. Call Open() before calling this method." , path);
681681
682+ // Add frame pointer to "queue", waiting to be processed the next
683+ // time the WriteFrames() method is called.
684+ if (info.has_video && video_st)
685+ spooled_video_frames.push_back (frame);
686+
687+ if (info.has_audio && audio_st)
688+ spooled_audio_frames.push_back (frame);
689+
682690 ZmqLogger::Instance ()->AppendDebugMethod (
683691 " FFmpegWriter::WriteFrame" ,
684692 " frame->number" , frame->number ,
693+ " spooled_video_frames.size()" , spooled_video_frames.size (),
694+ " spooled_audio_frames.size()" , spooled_audio_frames.size (),
695+ " cache_size" , cache_size,
685696 " is_writing" , is_writing);
686697
687- // Write frames to video file
688- write_frame (frame);
698+ // Write the frames once it reaches the correct cache size
699+ if ((int )spooled_video_frames.size () == cache_size || (int )spooled_audio_frames.size () == cache_size) {
700+ // Write frames to video file
701+ write_queued_frames ();
702+ }
689703
690704 // Keep track of the last frame added
691705 last_frame = frame;
692706}
693707
694708// Write all frames in the queue to the video file.
695- void FFmpegWriter::write_frame (std::shared_ptr<Frame> frame) {
709+ void FFmpegWriter::write_queued_frames () {
710+ ZmqLogger::Instance ()->AppendDebugMethod (
711+ " FFmpegWriter::write_queued_frames" ,
712+ " spooled_video_frames.size()" , spooled_video_frames.size (),
713+ " spooled_audio_frames.size()" , spooled_audio_frames.size ());
714+
696715 // Flip writing flag
697716 is_writing = true ;
698717
718+ // Transfer spool to queue
719+ queued_video_frames = spooled_video_frames;
720+ queued_audio_frames = spooled_audio_frames;
721+
722+ // Empty spool
723+ spooled_video_frames.clear ();
724+ spooled_audio_frames.clear ();
725+
699726 // Create blank exception
700727 bool has_error_encoding_video = false ;
701728
702- // Process audio frame
703- if (info.has_audio && audio_st)
704- write_audio_packets (false , frame );
729+ // Process all audio frames (in a separate thread)
730+ if (info.has_audio && audio_st && !queued_audio_frames. empty () )
731+ write_audio_packets (false );
705732
706- // Process video frame
707- if (info.has_video && video_st)
708- process_video_packet (frame);
733+ // Loop through each queued image frame
734+ while (!queued_video_frames.empty ()) {
735+ // Get front frame (from the queue)
736+ std::shared_ptr<Frame> frame = queued_video_frames.front ();
737+
738+ // Add to processed queue
739+ processed_frames.push_back (frame);
740+
741+ // Encode and add the frame to the output file
742+ if (info.has_video && video_st)
743+ process_video_packet (frame);
744+
745+ // Remove front item
746+ queued_video_frames.pop_front ();
747+
748+ } // end while
749+
750+
751+ // Loop back through the frames (in order), and write them to the video file
752+ while (!processed_frames.empty ()) {
753+ // Get front frame (from the queue)
754+ std::shared_ptr<Frame> frame = processed_frames.front ();
755+
756+ if (info.has_video && video_st) {
757+ // Add to deallocate queue (so we can remove the AVFrames when we are done)
758+ deallocate_frames.push_back (frame);
759+
760+ // Does this frame's AVFrame still exist
761+ if (av_frames.count (frame)) {
762+ // Get AVFrame
763+ AVFrame *frame_final = av_frames[frame];
764+
765+ // Write frame to video file
766+ bool success = write_video_packet (frame, frame_final);
767+ if (!success)
768+ has_error_encoding_video = true ;
769+ }
770+ }
771+
772+ // Remove front item
773+ processed_frames.pop_front ();
774+ }
775+
776+ // Loop through, and deallocate AVFrames
777+ while (!deallocate_frames.empty ()) {
778+ // Get front frame (from the queue)
779+ std::shared_ptr<Frame> frame = deallocate_frames.front ();
709780
710- if (info.has_video && video_st) {
711781 // Does this frame's AVFrame still exist
712782 if (av_frames.count (frame)) {
713783 // Get AVFrame
714- AVFrame *frame_final = av_frames[frame];
715-
716- // Write frame to video file
717- if (!write_video_packet (frame, frame_final)) {
718- has_error_encoding_video = true ;
719- }
784+ AVFrame *av_frame = av_frames[frame];
720785
721786 // Deallocate buffer and AVFrame
722- av_freep (&(frame_final ->data [0 ]));
723- AV_FREE_FRAME (&frame_final );
787+ av_freep (&(av_frame ->data [0 ]));
788+ AV_FREE_FRAME (&av_frame );
724789 av_frames.erase (frame);
725790 }
791+
792+ // Remove front item
793+ deallocate_frames.pop_front ();
726794 }
727795
728796 // Done writing
@@ -752,9 +820,12 @@ void FFmpegWriter::WriteFrame(ReaderBase *reader, int64_t start, int64_t length)
752820
753821// Write the file trailer (after all frames are written)
754822void FFmpegWriter::WriteTrailer () {
823+ // Write any remaining queued frames to video file
824+ write_queued_frames ();
825+
755826 // Process final audio frame (if any)
756827 if (info.has_audio && audio_st)
757- write_audio_packets (true , NULL );
828+ write_audio_packets (true );
758829
759830 // Flush encoders (who sometimes hold on to frames)
760831 flush_encoders ();
@@ -1527,10 +1598,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) {
15271598}
15281599
15291600// write all queued frames' audio to the video file
1530- void FFmpegWriter::write_audio_packets (bool is_final, std::shared_ptr<openshot::Frame> frame) {
1531- if (!frame && !is_final)
1532- return ;
1533-
1601+ void FFmpegWriter::write_audio_packets (bool is_final) {
15341602 // Init audio buffers / variables
15351603 int total_frame_samples = 0 ;
15361604 int frame_position = 0 ;
@@ -1540,49 +1608,56 @@ void FFmpegWriter::write_audio_packets(bool is_final, std::shared_ptr<openshot::
15401608 ChannelLayout channel_layout_in_frame = LAYOUT_MONO; // default channel layout
15411609
15421610 // Create a new array (to hold all S16 audio samples, for the current queued frames
1543- unsigned int all_queued_samples_size = sizeof (int16_t ) * AVCODEC_MAX_AUDIO_FRAME_SIZE;
1611+ unsigned int all_queued_samples_size = sizeof (int16_t ) * (queued_audio_frames. size () * AVCODEC_MAX_AUDIO_FRAME_SIZE) ;
15441612 int16_t *all_queued_samples = (int16_t *) av_malloc (all_queued_samples_size);
15451613 int16_t *all_resampled_samples = NULL ;
15461614 int16_t *final_samples_planar = NULL ;
15471615 int16_t *final_samples = NULL ;
15481616
1549- // Get audio sample array
1550- float *frame_samples_float = NULL ;
1617+ // Loop through each queued audio frame
1618+ while (!queued_audio_frames.empty ()) {
1619+ // Get front frame (from the queue)
1620+ std::shared_ptr<Frame> frame = queued_audio_frames.front ();
15511621
1552- // Get the audio details from this frame
1553- if (frame) {
1622+ // Get the audio details from this frame
15541623 sample_rate_in_frame = frame->SampleRate ();
15551624 samples_in_frame = frame->GetAudioSamplesCount ();
15561625 channels_in_frame = frame->GetAudioChannelsCount ();
15571626 channel_layout_in_frame = frame->ChannelsLayout ();
15581627
1628+ // Get audio sample array
1629+ float *frame_samples_float = NULL ;
15591630 // Get samples interleaved together (c1 c2 c1 c2 c1 c2)
15601631 frame_samples_float = frame->GetInterleavedAudioSamples (&samples_in_frame);
1561- }
15621632
1563- // Calculate total samples
1564- total_frame_samples = samples_in_frame * channels_in_frame;
1565-
1566- // Translate audio sample values back to 16 bit integers with saturation
1567- const int16_t max16 = 32767 ;
1568- const int16_t min16 = -32768 ;
1569- for (int s = 0 ; s < total_frame_samples; s++, frame_position++) {
1570- float valF = frame_samples_float[s] * (1 << 15 );
1571- int16_t conv;
1572- if (valF > max16) {
1573- conv = max16;
1574- } else if (valF < min16) {
1575- conv = min16;
1576- } else {
1577- conv = int (valF + 32768.5 ) - 32768 ; // +0.5 is for rounding
1633+ // Calculate total samples
1634+ total_frame_samples = samples_in_frame * channels_in_frame;
1635+
1636+ // Translate audio sample values back to 16 bit integers with saturation
1637+ const int16_t max16 = 32767 ;
1638+ const int16_t min16 = -32768 ;
1639+ for (int s = 0 ; s < total_frame_samples; s++, frame_position++) {
1640+ float valF = frame_samples_float[s] * (1 << 15 );
1641+ int16_t conv;
1642+ if (valF > max16) {
1643+ conv = max16;
1644+ } else if (valF < min16) {
1645+ conv = min16;
1646+ } else {
1647+ conv = int (valF + 32768.5 ) - 32768 ; // +0.5 is for rounding
1648+ }
1649+
1650+ // Copy into buffer
1651+ all_queued_samples[frame_position] = conv;
15781652 }
15791653
1580- // Copy into buffer
1581- all_queued_samples[frame_position] = conv;
1582- }
1654+ // Deallocate float array
1655+ delete[] frame_samples_float;
1656+
1657+ // Remove front item
1658+ queued_audio_frames.pop_front ();
15831659
1584- // Deallocate float array
1585- delete[] frame_samples_float;
1660+ } // end while
15861661
15871662
15881663 // Update total samples (since we've combined all queued frames)
0 commit comments