Added extra start frame to each chunk in the ChunkWriter and ChunkReader, to make sure every chunk can "stoke" the audio samples from the previous chunk. Also, added additional example code for an openshot::Frame.

This commit is contained in:
Jonathan Thomas
2013-09-15 22:21:19 -05:00
parent 9801c76878
commit 3596f75abc
5 changed files with 87 additions and 10 deletions

View File

@@ -88,6 +88,7 @@ namespace openshot
FFmpegWriter *writer_preview;
FFmpegWriter *writer_final;
tr1::shared_ptr<Frame> last_frame;
bool last_frame_needed;
string default_extension;
string default_vcodec;
string default_acodec;

View File

@@ -65,7 +65,55 @@ namespace openshot
* @brief This class represents a single frame of video (i.e. image & audio data)
*
* FileReaders (such as FFmpegReader) use instances of this class to store the individual frames of video,
* which include both the image data (i.e. pixels) and audio samples.
* which include both the image data (i.e. pixels) and audio samples. An openshot::Frame also has many debug
* methods, such as the ability to display the image (using X11), play the audio samples (using JUCE), or
* display the audio waveform as an image.
*
* FileWriters (such as FFmpegWriter) use instances of this class to create new video files, image files, or
* video streams. So, think of these openshot::Frame instances as the smallest unit of work in a video
* editor.
*
* There are many ways to create an instance of an openshot::Frame:
* @code
*
* // Most basic: a blank frame (300x200 blank image, 48kHz audio silence)
* Frame();
*
* // Image only settings (48kHz audio silence)
* Frame(1, // Frame number
* 720, // Width of image
* 480, // Height of image
* "#000000" // HTML color code of background color
* );
*
* // Image only from pixel array (48kHz audio silence)
* Frame(number, // Frame number
* 720, // Width of image
* 480, // Height of image
* "RGBA", // Color format / map
* Magick::CharPixel, // Storage format / data type
* buffer // Array of image data (pixels)
* );
*
* // Audio only (300x200 blank image)
* Frame(number, // Frame number
* 44100, // Sample rate of audio stream
* 2 // Number of audio channels
* );
*
* // Image and Audio settings (user defines all key settings)
* Frame(number, // Frame number
* 720, // Width of image
* 480, // Height of image
* "#000000" // HTML color code of background color
* 44100, // Sample rate of audio stream
* 2 // Number of audio channels
* );
*
* // Some methods require a shared pointer to an openshot::Frame object.
* tr1::shared_ptr<Frame> f(new Frame(1, 720, 480, "#000000", 44100, 2));
*
* @endcode
*/
class Frame
{

View File

@@ -128,12 +128,12 @@ void ChunkReader::load_json()
// Find the location of a frame in a chunk
ChunkLocation ChunkReader::find_chunk_frame(int requested_frame)
{
// Determine which chunk contains this frame
// Determine which chunk contains this frame.
int chunk_number = (requested_frame / chunk_size) + 1;
// Determine which frame in this chunk
int start_frame_of_chunk = (chunk_number - 1) * chunk_size;
int chunk_frame_number = requested_frame - start_frame_of_chunk;
int chunk_frame_number = (requested_frame - start_frame_of_chunk) + 1; // Add 1 to adjust for the 1st frame of every chunk is just there to "stoke" the audio samples from the previous chunk.
// Prepare chunk location struct
ChunkLocation location = {chunk_number, chunk_frame_number};

View File

@@ -31,7 +31,7 @@ using namespace openshot;
ChunkWriter::ChunkWriter(string path, ReaderBase *reader) throw (InvalidFile, InvalidFormat, InvalidCodec, InvalidOptions, OutOfMemory) :
local_reader(reader), path(path), chunk_size(24*3), chunk_count(1), frame_count(1), is_writing(false),
default_extension(".webm"), default_vcodec("libvpx"), default_acodec("libvorbis")
default_extension(".webm"), default_vcodec("libvpx"), default_acodec("libvorbis"), last_frame_needed(false)
{
// Init FileInfo struct (clear all values)
InitFileInfo();
@@ -107,14 +107,42 @@ void ChunkWriter::WriteFrame(tr1::shared_ptr<Frame> frame)
writer_preview->WriteHeader();
writer_thumb->WriteHeader();
// Keep track that a chunk is being writen
// Keep track that a chunk is being written
is_writing = true;
last_frame_needed = true;
}
// Write a frame to the current chunk
// If this is not the 1st chunk, always start frame 1 with the last frame from the previous
// chunk. This helps to prevent audio resampling issues (because it "stokes" the sample array)
if (last_frame_needed)
{
if (last_frame)
{
// Write the previous chunks LAST FRAME to the current chunk
writer_final->WriteFrame(last_frame);
writer_preview->WriteFrame(last_frame);
writer_thumb->WriteFrame(last_frame);
} else {
// Write the 1st frame (of the 1st chunk)... since no previous chunk is available
tr1::shared_ptr<Frame> blank_frame(new Frame(1, info.width, info.height, "#000000", info.sample_rate, info.channels));
blank_frame->AddColor(info.width, info.height, "#000000");
writer_final->WriteFrame(blank_frame);
writer_preview->WriteFrame(blank_frame);
writer_thumb->WriteFrame(blank_frame);
}
// disable last frame
last_frame_needed = false;
}
//////////////////////////////////////////////////
// WRITE THE CURRENT FRAME TO THE CURRENT CHUNK
writer_final->WriteFrame(frame);
writer_preview->WriteFrame(frame);
writer_thumb->WriteFrame(frame);
//////////////////////////////////////////////////
// Write the frames once it reaches the correct chunk size
if (frame_count % chunk_size == 0 && frame_count >= chunk_size)

View File

@@ -49,7 +49,7 @@ int main(int argc, char* argv[])
// FFmpegReader *r3 = new FFmpegReader("/home/jonathan/Videos/sintel_trailer-720p.mp4");
// r3->DisplayInfo();
// ChunkWriter cw1("/home/jonathan/apps/chunks/chunk1/", r3);
// cw1.WriteFrame(r3, 1, r3->info.video_length);
// cw1.WriteFrame(r3, 1, r3->info.video_length - 45);
// cw1.Close();
// return 0;
@@ -77,11 +77,11 @@ int main(int argc, char* argv[])
//cr1.GetFrame(300)->Display();
/* WRITER ---------------- */
FFmpegWriter w9("/home/jonathan/fromchunks.mp3");
FFmpegWriter w9("/home/jonathan/fromchunks.webm");
// Set options
w9.SetAudioOptions(true, "libmp3lame", cr1.info.sample_rate, cr1.info.channels, cr1.info.audio_bit_rate);
//w9.SetVideoOptions(true, cr1.info.vcodec, cr1.info.fps, cr1.info.width, cr1.info.height, cr1.info.pixel_ratio, false, false, cr1.info.video_bit_rate);
w9.SetAudioOptions(true, "libvorbis", cr1.info.sample_rate, cr1.info.channels, cr1.info.audio_bit_rate);
w9.SetVideoOptions(true, cr1.info.vcodec, cr1.info.fps, cr1.info.width, cr1.info.height, cr1.info.pixel_ratio, false, false, cr1.info.video_bit_rate);
// Prepare Streams
w9.PrepareStreams();