Skip to content

Commit 038dd17

Browse files
committed
Reverting changes to FFmpegWriter to test unit tests on GitHub builder
1 parent 511e1ff commit 038dd17

File tree

2 files changed

+144
-52
lines changed

2 files changed

+144
-52
lines changed

src/FFmpegWriter.cpp

Lines changed: 125 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6
7575
FFmpegWriter::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)
754822
void 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)

src/FFmpegWriter.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ namespace openshot {
116116
class FFmpegWriter : public WriterBase {
117117
private:
118118
std::string path;
119+
int cache_size;
119120
bool is_writing;
120121
bool is_open;
121122
int64_t video_timestamp;
@@ -151,6 +152,15 @@ namespace openshot {
151152
int original_channels;
152153

153154
std::shared_ptr<openshot::Frame> last_frame;
155+
std::deque<std::shared_ptr<openshot::Frame> > spooled_audio_frames;
156+
std::deque<std::shared_ptr<openshot::Frame> > spooled_video_frames;
157+
158+
std::deque<std::shared_ptr<openshot::Frame> > queued_audio_frames;
159+
std::deque<std::shared_ptr<openshot::Frame> > queued_video_frames;
160+
161+
std::deque<std::shared_ptr<openshot::Frame> > processed_frames;
162+
std::deque<std::shared_ptr<openshot::Frame> > deallocate_frames;
163+
154164
std::map<std::shared_ptr<openshot::Frame>, AVFrame *> av_frames;
155165

156166
/// Add an AVFrame to the cache
@@ -195,13 +205,13 @@ namespace openshot {
195205
void process_video_packet(std::shared_ptr<openshot::Frame> frame);
196206

197207
/// write all queued frames' audio to the video file
198-
void write_audio_packets(bool is_final, std::shared_ptr<openshot::Frame> frame);
208+
void write_audio_packets(bool is_final);
199209

200210
/// write video frame
201211
bool write_video_packet(std::shared_ptr<openshot::Frame> frame, AVFrame *frame_final);
202212

203213
/// write all queued frames
204-
void write_frame(std::shared_ptr<Frame> frame);
214+
void write_queued_frames();
205215

206216
public:
207217

@@ -214,6 +224,9 @@ namespace openshot {
214224
/// Close the writer
215225
void Close();
216226

227+
/// Get the cache size (number of frames to queue before writing)
228+
int GetCacheSize() { return cache_size; };
229+
217230
/// Determine if writer is open or closed
218231
bool IsOpen() { return is_open; };
219232

@@ -260,6 +273,10 @@ namespace openshot {
260273
/// \note This is an overloaded function.
261274
void SetAudioOptions(std::string codec, int sample_rate, int bit_rate);
262275

276+
/// @brief Set the cache size
277+
/// @param new_size The number of frames to queue before writing to the file
278+
void SetCacheSize(int new_size) { cache_size = new_size; };
279+
263280
/// @brief Set video export options
264281
/// @param has_video Does this file need a video stream
265282
/// @param codec The codec used to encode the images in this video

0 commit comments

Comments
 (0)