Some major refactoing of the FFmpegReader, to allow for audio and video packets that are out of order.

This commit is contained in:
Jonathan Thomas
2011-10-24 08:22:21 -05:00
parent 1faa168fb3
commit 43fd6c33d0
8 changed files with 434 additions and 168 deletions

View File

@@ -44,9 +44,15 @@ namespace openshot {
/// Check for the existance of a frame in the cache
bool Exists(int frame_number);
/// Return the front frame and remove it
Frame Pop();
/// Get a frame from the cache
Frame GetFrame(int frame_number);
/// Get the front frame in this cache
Frame GetFront();
/// Clear the cache of all frames
void Clear();

View File

@@ -33,6 +33,14 @@ using namespace std;
namespace openshot
{
/// This struct holds the associated video frame and starting sample # for an audio packet.
/// Because audio packets do not match up with video frames, this helps determine exactly
/// where the audio packet's samples belong.
struct audio_packet_location
{
int frame;
int sample_start;
};
/**
* \brief This class uses the FFmpeg libraries, to open video files and audio files, and return
@@ -56,39 +64,55 @@ namespace openshot
AVPacket packet;
AVFrame *pFrame;
Frame new_frame;
Cache final_cache;
Cache working_cache;
bool is_seeking;
int seeking_pts;
int seeking_frame;
bool is_video_seek;
bool found_pts_offset;
int pts_offset;
int audio_pts_offset;
int video_pts_offset;
int last_video_frame;
int last_audio_frame;
bool found_frame;
int current_frame;
int current_pts;
int audio_position;
bool needs_packet;
/// Open File - which is called by the constructor automatically
void Open();
/// Convert image to RGB format
Frame convert_image(AVPicture *copyFrame, int original_width, int original_height, PixelFormat pix_fmt);
void convert_image(int current_frame, AVPicture *copyFrame, int width, int height, PixelFormat pix_fmt);
/// Convert PTS into Frame Number
int ConvertPTStoFrame(int pts);
/// Get the PTS for the current video packet
int GetVideoPTS();
/// Convert Frame Number into PTS
int ConvertFrameToPTS(int frame_number);
/// Update PTS Offset (if any)
void UpdatePTSOffset(bool is_video);
/// Calculate Starting video frame for an audio PTS
int GetFrameFromAudioPTS(int pts);
/// Convert Video PTS into Frame Number
int ConvertVideoPTStoFrame(int pts);
/// Convert Frame Number into Video PTS
int ConvertFrameToVideoPTS(int frame_number);
/// Convert Frame Number into Audio PTS
int ConvertFrameToAudioPTS(int frame_number);
/// Calculate Starting video frame and sample # for an audio PTS
audio_packet_location GetAudioPTSLocation(int pts);
/// Calculate the # of samples per video frame
int GetSamplesPerFrame();
/// Create a new Frame (or return an existing one) and add it to the working queue.
Frame CreateFrame(int requested_frame);
/// Check the working queue, and move finished frames to the finished queue
void CheckWorkingFrames(bool end_of_stream);
public:
/// Constructor for FFmpegReader. This automatically opens the media file and loads
/// frame 1, or it throws one of the following exceptions.
@@ -119,19 +143,16 @@ namespace openshot
void ProcessVideoPacket(int requested_frame);
/// Process an audio packet
void ProcessAudioPacket(int requested_frame);
void ProcessAudioPacket(int requested_frame, int target_frame, int starting_sample);
/// Get the next packet (if any)
int GetNextPacket();
/// Set the frame number and current pts
void SetFrameNumber();
/// Get an AVFrame (if any)
bool GetAVFrame();
/// Check the current seek position and determine if we need to seek again
bool CheckSeek();
bool CheckSeek(bool is_video);
};

View File

@@ -36,7 +36,6 @@ namespace openshot
public:
int number; ///< This is the frame number (starting at 1)
int pts; ///< This is the presentation timestamp (in frames)
/// Constructor - blank frame (300x200 blank image, 48kHz audio silence)
Frame();
@@ -45,7 +44,7 @@ namespace openshot
Frame(int number, int width, int height, string color);
/// Constructor - image only from pixel array (48kHz audio silence)
Frame(int number, int pts, int width, int height, const string map, const Magick::StorageType type, const void *pixels_);
Frame(int number, int width, int height, const string map, const Magick::StorageType type, const void *pixels_);
/// Constructor - audio only (300x200 blank image)
Frame(int number, int samples, int channels);
@@ -89,6 +88,9 @@ namespace openshot
/// Save the frame image
void Save();
/// Add (or replace) pixel data to the frame
void AddImage(int width, int height, const string map, const Magick::StorageType type, const void *pixels_);
/// Add audio samples to a specific channel
void AddAudio(int destChannel, int destStartSample, const float* source, int numSamples, float gainToApplyToSource);

View File

@@ -46,6 +46,23 @@ bool Cache::Exists(int frame_number)
return false;
}
// Return the front frame and remove it
Frame Cache::Pop()
{
// Remove the oldest frame
int frame_to_remove = frame_numbers.front();
// Get the front frame
Frame f = GetFrame(frame_to_remove);
// Remove frame_number and frame
frame_numbers.pop();
frames.erase(frame_to_remove);
// Return the frame
return f;
}
// Get a frame from the cache
Frame Cache::GetFrame(int frame_number)
{
@@ -60,6 +77,13 @@ Frame Cache::GetFrame(int frame_number)
throw OutOfBoundsFrame("Frame not found in the cache", frame_number, -1);
}
// Get the front frame in this cache
Frame Cache::GetFront()
{
// Return oldest frame in the cache
return GetFrame(frame_numbers.front());
}
// Clear the cache of all frames
void Cache::Clear()
{

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@ using namespace std;
using namespace openshot;
// Constructor - blank frame (300x200 blank image, 48kHz audio silence)
Frame::Frame() : number(1), pts(0), image(0), audio(0)
Frame::Frame() : number(1), image(0), audio(0)
{
// Init the image magic and audio buffer
image = new Magick::Image(Magick::Geometry(300,200), Magick::Color("red"));
@@ -21,7 +21,7 @@ Frame::Frame() : number(1), pts(0), image(0), audio(0)
};
// Constructor - image only (48kHz audio silence)
Frame::Frame(int number, int width, int height, string color) : number(number), pts(0), image(0), audio(0)
Frame::Frame(int number, int width, int height, string color) : number(number), image(0), audio(0)
{
// Init the image magic and audio buffer
image = new Magick::Image(Magick::Geometry(width, height), Magick::Color(color));
@@ -32,8 +32,8 @@ Frame::Frame(int number, int width, int height, string color) : number(number),
};
// Constructor - image only from pixel array (48kHz audio silence)
Frame::Frame(int number, int pts, int width, int height, const string map, const Magick::StorageType type, const void *pixels)
: number(number), pts(pts), image(0), audio(0)
Frame::Frame(int number, int width, int height, const string map, const Magick::StorageType type, const void *pixels)
: number(number), image(0), audio(0)
{
// Init the image magic and audio buffer
image = new Magick::Image(width, height, map, type, pixels);
@@ -44,7 +44,7 @@ Frame::Frame(int number, int pts, int width, int height, const string map, const
};
// Constructor - audio only (300x200 blank image)
Frame::Frame(int number, int samples, int channels) : number(number), pts(0), image(0), audio(0)
Frame::Frame(int number, int samples, int channels) : number(number), image(0), audio(0)
{
// Init the image magic and audio buffer
image = new Magick::Image(Magick::Geometry(300, 200), Magick::Color("white"));
@@ -55,7 +55,7 @@ Frame::Frame(int number, int samples, int channels) : number(number), pts(0), im
};
// Constructor - image & audio
Frame::Frame(int number, int width, int height, string color, int samples, int channels) : number(number), pts(0), image(0), audio(0)
Frame::Frame(int number, int width, int height, string color, int samples, int channels) : number(number), image(0), audio(0)
{
// Init the image magic and audio buffer
image = new Magick::Image(Magick::Geometry(width, height), Magick::Color(color));
@@ -176,6 +176,17 @@ void Frame::Save()
image->write(file.str());
}
// Add (or replace) pixel data to the frame
void Frame::AddImage(int width, int height, const string map, const Magick::StorageType type, const void *pixels)
{
// Deallocate image memory
delete image;
image = NULL;
// Create new image object, and fill with pixel data
image = new Magick::Image(width, height, map, type, pixels);
}
// Add audio samples to a specific channel
void Frame::AddAudio(int destChannel, int destStartSample, const float* source, int numSamples, float gainToApplyToSource = 1.0f)
{

View File

@@ -28,11 +28,8 @@ int main()
// Display debug info
r.DisplayInfo();
r.GetFrame(300);
r.GetFrame(300);
r.GetFrame(301);
r.GetFrame(302);
r.GetFrame(5);
r.GetFrame(1).Display();
r.GetFrame(300).Display();
//Player g;
//g.SetReader(&r);

View File

@@ -121,3 +121,56 @@ TEST(Cache_GetFrame)
CHECK_EQUAL(3, c.GetFrame(3).number);
}
TEST(Cache_GetFront)
{
// Create cache object (with a max of 10 items)
Cache c(10);
// Create 3 frames
Frame red(1, 300, 300, "red");
Frame blue(2, 400, 400, "blue");
Frame green(3, 500, 500, "green");
// Add frames to cache
c.Add(red.number, red);
c.Add(blue.number, blue);
c.Add(green.number, green);
// Check if frame 1 is the front
CHECK_EQUAL(1, c.GetFront().number);
// Check if frame 1 is STILL the front
CHECK_EQUAL(1, c.GetFront().number);
// Erase frame 1
c.Pop();
// Check if frame 2 is the front
CHECK_EQUAL(2, c.GetFront().number);
}
TEST(Cache_Pop)
{
// Create cache object (with a max of 10 items)
Cache c(10);
// Create 3 frames
Frame red(1, 300, 300, "red");
Frame blue(2, 400, 400, "blue");
Frame green(3, 500, 500, "green");
// Add frames to cache
c.Add(red.number, red);
c.Add(blue.number, blue);
c.Add(green.number, green);
// Check if frame 1 is the front
Frame pop1 = c.Pop();
CHECK_EQUAL(1, pop1.number);
Frame pop2 = c.Pop();
CHECK_EQUAL(2, pop2.number);
Frame pop3 = c.Pop();
CHECK_EQUAL(3, pop3.number);
}