Fixed many bugs on the multi-threaded encoder, simplified the API, and removed some memory leaks.

This commit is contained in:
Jonathan Thomas
2012-08-20 14:26:49 -05:00
parent 97b2717744
commit b98b8f8968
6 changed files with 76 additions and 58 deletions

View File

@@ -55,6 +55,7 @@ namespace openshot
{
private:
string path;
int cache_size;
AVOutputFormat *fmt;
AVFormatContext *oc;
@@ -115,7 +116,8 @@ namespace openshot
/// write video frame
void write_video_packet(Frame* frame, AVFrame* frame_final);
/// write all queued frames
void write_queued_frames();
public:
@@ -125,12 +127,18 @@ namespace openshot
/// Close the writer
void Close();
/// Get the cache size (number of frames to queue before writing)
int GetCacheSize() { return cache_size; };
/// Output the ffmpeg info about this format, streams, and codecs (i.e. dump format)
void OutputStreamInfo();
/// Set audio export options
void SetAudioOptions(bool has_audio, string codec, int sample_rate, int channels, int bit_rate);
/// Set the cache size (number of frames to queue before writing)
int SetCacheSize(int new_size) { cache_size = new_size; };
/// Set video export options
void SetVideoOptions(bool has_video, string codec, Fraction fps, int width, int height,
Fraction pixel_ratio, bool interlaced, bool top_field_first, int bit_rate);
@@ -145,13 +153,10 @@ namespace openshot
void WriteHeader();
/// Add a frame to the stack waiting to be encoded.
void AddFrame(Frame* frame);
/// Write all frames on the stack to the video file.
void WriteFrames();
void WriteFrame(Frame* frame);
/// Write a block of frames from a reader
//void WriteFrame(FileReaderBase* reader, int start, int length);
void WriteFrame(FileReaderBase* reader, int start, int length);
/// Write the file trailer (after all frames are written)
void WriteTrailer();

View File

@@ -11,6 +11,7 @@
#include <iomanip>
#include "Fraction.h"
#include "Frame.h"
#include "FileReaderBase.h"
using namespace std;
@@ -62,13 +63,11 @@ namespace openshot
/// Information about the current media file
WriterInfo info;
/// This method is required for all derived classes of FileWriterBase. Add a frame to the stack
/// waiting to be encoded.
virtual void AddFrame(Frame* frame) = 0;
/// This method is required for all derived classes of FileWriterBase. Write a Frame to the video file.
virtual void WriteFrame(Frame* frame) = 0;
/// This method is required for all derived classes of FileWriterBase. Write all frames on the
/// stack.
virtual void WriteFrames() = 0;
/// This method is required for all derived classes of FileWriterBase. Write a block of frames from a reader.
virtual void WriteFrame(FileReaderBase* reader, int start, int length) = 0;
/// Initialize the values of the WriterInfo struct. It is important for derived classes to call
/// this method, or the WriterInfo struct values will not be initialized.

View File

@@ -34,7 +34,8 @@ FIND_PACKAGE(OpenMP)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
############### PROFILING #################
#set(PROFILER "/usr/lib/libprofiler.so")
set(PROFILER "/usr/lib/libprofiler.so")
#set(PROFILER "/usr/lib/libtcmalloc.so")
############### CREATE LIBRARY #################
# Create shared openshot library

View File

@@ -30,7 +30,7 @@ using namespace openshot;
FFmpegWriter::FFmpegWriter(string path) throw (InvalidFile, InvalidFormat, InvalidCodec, InvalidOptions, OutOfMemory) :
path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), audio_pts(0), video_pts(0), samples(NULL),
audio_outbuf(NULL), audio_outbuf_size(0), audio_input_frame_size(0), audio_input_position(0),
initial_audio_input_frame_size(0), resampler(NULL), img_convert_ctx(NULL)
initial_audio_input_frame_size(0), resampler(NULL), img_convert_ctx(NULL), cache_size(12)
{
// Init FileInfo struct (clear all values)
@@ -282,7 +282,7 @@ void FFmpegWriter::WriteHeader()
}
// Add a frame to the queue waiting to be encoded.
void FFmpegWriter::AddFrame(Frame* frame)
void FFmpegWriter::WriteFrame(Frame* frame)
{
// Add frame pointer to "queue", waiting to be processed the next
// time the WriteFrames() method is called.
@@ -291,10 +291,15 @@ void FFmpegWriter::AddFrame(Frame* frame)
if (info.has_audio && audio_st)
audio_frames.push_back(frame);
// Write the frames once it reaches the correct cache size
if (queued_frames.size() == cache_size)
// Write frames to video file
write_queued_frames();
}
// Write all frames in the queue to the video file.
void FFmpegWriter::WriteFrames()
void FFmpegWriter::write_queued_frames()
{
//omp_set_num_threads(1);
#pragma omp parallel
@@ -342,11 +347,15 @@ void FFmpegWriter::WriteFrames()
// Add to deallocate queue (so we can remove the AVFrames when we are done)
deallocate_frames.push_back(frame);
// Get AVFrame
AVFrame *frame_final = av_frames[frame];
// Does this frame's AVFrame still exist
if (av_frames.count(frame))
{
// Get AVFrame
AVFrame *frame_final = av_frames[frame];
// Write frame to video file
write_video_packet(frame, frame_final);
// Write frame to video file
write_video_packet(frame, frame_final);
}
}
// Remove front item
@@ -379,22 +388,25 @@ void FFmpegWriter::WriteFrames()
}
// Write a block of frames from a reader
//void FFmpegWriter::WriteFrame(FileReaderBase* reader, int start, int length)
//{
// // Loop through each frame (and encoded it)
// for (int number = start; number <= length; number++)
// {
// // Get the frame
// Frame *f = reader->GetFrame(number);
//
// // Encode frame
// WriteFrame(f);
// }
//}
void FFmpegWriter::WriteFrame(FileReaderBase* reader, int start, int length)
{
// Loop through each frame (and encoded it)
for (int number = start; number <= length; number++)
{
// Get the frame
Frame *f = reader->GetFrame(number);
// Encode frame
WriteFrame(f);
}
}
// Write the file trailer (after all frames are written)
void FFmpegWriter::WriteTrailer()
{
// Write any remaining queued frames to video file
write_queued_frames();
/* write the trailer, if any. the trailer must be written
* before you close the CodecContexts open when you wrote the
* header; otherwise write_trailer may try to use memory that
@@ -459,8 +471,10 @@ void FFmpegWriter::add_avframe(Frame* frame, AVFrame* av_frame)
{
// Add AVFrame to map (if it does not already exist)
if (!av_frames.count(frame))
// Add
{
// Add av_frame
av_frames[frame] = av_frame;
}
else
{
// Do not add, and deallocate this AVFrame
@@ -683,9 +697,9 @@ void FFmpegWriter::write_audio_packets()
c = audio_st->codec;
// Create a resampler (only once)
if (!resampler)
resampler = new AudioResampler();
AudioResampler *new_sampler = resampler;
if (!new_sampler)
new_sampler = new AudioResampler();
#pragma omp task firstprivate(c, new_sampler)
{
@@ -715,6 +729,7 @@ void FFmpegWriter::write_audio_packets()
channels_in_frame = frame->GetAudioChannelsCount();
// Get audio sample array
//float* frame_samples_float = new float(total_frame_samples);
float* frame_samples_float = frame->GetInterleavedAudioSamples(info.sample_rate, new_sampler, &samples_in_frame);
// Calculate total samples
@@ -867,12 +882,12 @@ void FFmpegWriter::process_video_packet(Frame* frame)
c = video_st->codec;
// Initialize the software scaler (if needed)
SwsContext *scaler = img_convert_ctx;
if (!scaler)
if (!img_convert_ctx)
// Init the software scaler from FFMpeg
scaler = sws_getContext(frame->GetWidth(), frame->GetHeight(), PIX_FMT_RGB24, info.width, info.height, c->pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
if (scaler == NULL)
img_convert_ctx = sws_getContext(frame->GetWidth(), frame->GetHeight(), PIX_FMT_RGB24, info.width, info.height, c->pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
if (img_convert_ctx == NULL)
throw OutOfMemory("Could not allocate SwsContext.", path);
SwsContext *scaler = img_convert_ctx;
#pragma omp task firstprivate(frame, c, scaler)
{

View File

@@ -294,6 +294,13 @@ float* Frame::GetInterleavedAudioSamples(int new_sample_rate, AudioResampler* re
}
}
// Clear resampled buffer (if any)
if (resampled_buffer)
{
resampled_buffer->clear();
delete resampled_buffer;
}
// Update sample count (since it might have changed due to resampling)
*sample_count = num_of_samples;
@@ -322,14 +329,14 @@ int Frame::GetAudioSamplesRate()
// Get pixel data (as packets)
const Magick::PixelPacket* Frame::GetPixels()
{
// Return arry of pixel packets
// Return array of pixel packets
return image->getConstPixels(0,0, image->columns(), image->rows());
}
// Get pixel data (for only a single scan-line)
const Magick::PixelPacket* Frame::GetPixels(int row)
{
// Return arry of pixel packets
// Return array of pixel packets
return image->getConstPixels(0,row, image->columns(), 1);
}
@@ -343,9 +350,9 @@ const Magick::PixelPacket* Frame::GetPixels(unsigned int width, unsigned int hei
small_image->colorize(255, 0, 0, Magick::Color(0,0,255));
small_image->blur(5.0, 5.0);
stringstream file;
file << "frame" << frame << ".png";
small_image->write(file.str());
// stringstream file;
// file << "frame" << frame << ".png";
// small_image->write(file.str());
// Return arry of pixel packets
return small_image->getConstPixels(0,0, small_image->columns(), small_image->rows());

View File

@@ -20,9 +20,9 @@ int main()
// openshot::FFmpegReader r("../../src/examples/piano.wav");
// openshot::FFmpegReader r("/home/jonathan/Videos/big-buck-bunny_trailer.webm");
openshot::FFmpegReader r("/home/jonathan/Videos/sintel-1024-stereo.mp4");
// openshot::FFmpegReader r("/home/jonathan/Videos/sintel-1024-stereo.mp4");
// openshot::FFmpegReader r("/home/jonathan/Videos/00001.mts");
// openshot::FFmpegReader r("/home/jonathan/Videos/sintel_trailer-720p.mp4");
openshot::FFmpegReader r("/home/jonathan/Videos/sintel_trailer-720p.mp4");
// openshot::FFmpegReader r("/home/jonathan/Aptana Studio Workspace/OpenShotLibrary/src/examples/piano.wav");
// openshot::FFmpegReader r("/home/jonathan/Music/Army of Lovers/Crucified/Army of Lovers - Crucified [Single Version].mp3");
// openshot::FFmpegReader r("/home/jonathan/Documents/OpenShot Art/test.jpeg");
@@ -38,7 +38,7 @@ int main()
// Set options
w.SetAudioOptions(true, "libvorbis", 44100, 2, 128000);
w.SetVideoOptions(true, "libvpx", Fraction(25, 1), 640, 360, Fraction(1,1), false, false, 2000000);
w.SetVideoOptions(true, "libvpx", Fraction(24, 1), 640, 360, Fraction(1,1), false, false, 2000000);
// Prepare Streams
w.PrepareStreams();
@@ -67,7 +67,7 @@ int main()
//Frame *f = r.GetFrame(1);
for (int frame = 1; frame <= 500; frame++)
for (int frame = 1; frame <= 1000; frame++)
{
Frame *f = r.GetFrame(frame);
@@ -76,19 +76,10 @@ int main()
// Write frame
cout << "queue frame " << frame << endl;
w.AddFrame(f);
w.WriteFrame(f);
if (frame % 12 == 0)
{
cout << "-- Writing frames --" << endl;
w.WriteFrames();
}
}
// Write remaining frames
w.WriteFrames();
w.WriteFrames();
// Write Footer
w.WriteTrailer();