initial chunck readers/writers

This commit is contained in:
Jonathan Thomas
2013-07-31 12:45:47 -05:00
parent 616be34fd6
commit bcfbe60a4a
10 changed files with 438 additions and 0 deletions

58
include/ChunkReader.h Normal file
View File

@@ -0,0 +1,58 @@
#ifndef OPENSHOT_CHUNK_READER_H
#define OPENSHOT_CHUNK_READER_H
/**
* \file
* \brief Header file for ChunkReader class
* \author Copyright (c) 2013 Jonathan Thomas
*/
#include "FileReaderBase.h"
#include <cmath>
#include <ctime>
#include <iostream>
#include <omp.h>
#include <stdio.h>
#include <tr1/memory>
#include "Magick++.h"
#include "Cache.h"
#include "Exceptions.h"
using namespace std;
namespace openshot
{
/**
* \brief This class reads a special chunk-formatted file, which can be easily
* shared in a distributed environment, and can return openshot::Frame objects.
*/
class ChunkReader : public FileReaderBase
{
private:
string path;
bool is_open;
public:
/// Constructor for ChunkReader. This automatically opens the chunk file or folder and loads
/// frame 1, or it throws one of the following exceptions.
ChunkReader(string path) throw(InvalidFile);
/// Close Reader
void Close();
/// Get an openshot::Frame object for a specific frame number of this reader.
///
/// @returns The requested frame (containing the image)
/// @param[requested_frame] number The frame number that is requested.
tr1::shared_ptr<Frame> GetFrame(int requested_frame) throw(ReaderClosed);
/// Open File - which is called by the constructor automatically
void Open() throw(InvalidFile);
};
}
#endif

79
include/ChunkWriter.h Normal file
View File

@@ -0,0 +1,79 @@
#ifndef OPENSHOT_CHUNK_WRITER_H
#define OPENSHOT_CHUNK_WRITER_H
/**
* \file
* \brief Header file for ChunkWriter class
* \author Copyright (c) 2013 Jonathan Thomas
*/
#include "FileReaderBase.h"
#include "FileWriterBase.h"
#include <cmath>
#include <ctime>
#include <iostream>
#include <omp.h>
#include <stdio.h>
#include <sstream>
#include <unistd.h>
#include "Magick++.h"
#include "Cache.h"
#include "Exceptions.h"
#include "Sleep.h"
using namespace std;
namespace openshot
{
/**
* \brief This class takes any reader and generates a special type of video file, built with
* chunks of small video and audio data. These chunks can easily be passed around in a distributed
* computing environment, without needing to share the entire video file.
*/
class ChunkWriter : public FileWriterBase
{
private:
string path;
int cache_size;
bool is_writing;
int64 write_video_count;
int64 write_audio_count;
tr1::shared_ptr<Frame> last_frame;
deque<tr1::shared_ptr<Frame> > spooled_frames;
deque<tr1::shared_ptr<Frame> > queued_frames;
deque<tr1::shared_ptr<Frame> > processed_frames;
/// process video frame
void process_frame(tr1::shared_ptr<Frame> frame);
/// write all queued frames
void write_queued_frames();
public:
/// Constructor for ChunkWriter. Throws one of the following exceptions.
ChunkWriter(FileReaderBase *reader, string path) throw(InvalidFile, InvalidFormat, InvalidCodec, InvalidOptions, OutOfMemory);
/// Close the writer
void Close();
/// Get the cache size (number of frames to queue before writing)
int GetCacheSize() { return cache_size; };
/// Set the cache size (number of frames to queue before writing)
int SetCacheSize(int new_size) { cache_size = new_size; };
/// Add a frame to the stack waiting to be encoded.
void WriteFrame(tr1::shared_ptr<Frame> frame);
/// Write a block of frames from a reader
void WriteFrame(FileReaderBase* reader, int start, int length);
};
}
#endif

View File

@@ -63,6 +63,9 @@ namespace openshot
/// Information about the current media file
WriterInfo info;
/// This method copy's the info struct of a reader, and sets the writer with the same info
void CopyReaderInfo(FileReaderBase* reader);
/// This method is required for all derived classes of FileWriterBase. Write a Frame to the video file.
virtual void WriteFrame(tr1::shared_ptr<Frame> frame) = 0;

View File

@@ -28,6 +28,7 @@
#include "AudioBufferSource.h"
#include "AudioResampler.h"
#include "Cache.h"
#include "ChunkWriter.h"
#include "Clip.h"
#include "Coordinate.h"
#ifdef USE_BLACKMAGIC

View File

@@ -59,6 +59,7 @@ SET ( OPENSHOT_SOURCE_FILES
AudioBufferSource.cpp
AudioResampler.cpp
Cache.cpp
ChunkWriter.cpp
Clip.cpp
Coordinate.cpp
DummyReader.cpp

99
src/ChunkReader.cpp Normal file
View File

@@ -0,0 +1,99 @@
#include "../include/ChunkReader.h"
using namespace openshot;
ChunkReader::ChunkReader(string path) throw(InvalidFile) : path(path), is_open(false)
{
// Init FileInfo struct (clear all values)
InitFileInfo();
// Open and Close the reader, to populate it's attributes (such as height, width, etc...)
Open();
Close();
}
// Open chunk folder or file
void ChunkReader::Open() throw(InvalidFile)
{
// Open reader if not already open
if (!is_open)
{
// Attempt to open file
try
{
// load chunk
image = tr1::shared_ptr<Magick::Image>(new Magick::Image(path));
// Give image a transparent background color
image->backgroundColor(Magick::Color("none"));
}
catch (Magick::Exception e) {
// raise exception
throw InvalidFile("File could not be opened.", path);
}
// Update image properties
info.has_audio = false;
info.has_video = true;
info.file_size = image->fileSize();
info.vcodec = image->format();
info.width = image->size().width();
info.height = image->size().height();
info.pixel_ratio.num = 1;
info.pixel_ratio.den = 1;
info.duration = 60 * 60 * 24; // 24 hour duration
info.fps.num = 30;
info.fps.den = 1;
info.video_timebase.num = 1;
info.video_timebase.den = 30;
info.video_length = round(info.duration * info.fps.ToDouble());
// Calculate the DAR (display aspect ratio)
Fraction size(info.width * info.pixel_ratio.num, info.height * info.pixel_ratio.den);
// Reduce size fraction
size.Reduce();
// Set the ratio based on the reduced fraction
info.display_ratio.num = size.num;
info.display_ratio.den = size.den;
// Mark as "open"
is_open = true;
}
}
// Close image file
void ChunkReader::Close()
{
// Close all objects, if reader is 'open'
if (is_open)
{
// Mark as "closed"
is_open = false;
}
}
// Get an openshot::Frame object for a specific frame number of this reader.
tr1::shared_ptr<Frame> ChunkReader::GetFrame(int requested_frame) throw(ReaderClosed)
{
if (image)
{
// Create or get frame object
tr1::shared_ptr<Frame> image_frame(new Frame(requested_frame, image->size().width(), image->size().height(), "#000000", 0, 2));
image_frame->SetSampleRate(44100);
// Add Image data to frame
tr1::shared_ptr<Magick::Image> copy_image(new Magick::Image(*image.get()));
copy_image->modifyImage(); // actually copy the image data to this object
image_frame->AddImage(copy_image);
// return frame object
return image_frame;
}
else
// no frame loaded
throw InvalidFile("No frame could be created from this type of file.", path);
}

152
src/ChunkWriter.cpp Normal file
View File

@@ -0,0 +1,152 @@
/**
* \file
* \brief Source code for the ChunkWriter class
* \author Copyright (c) 2013 Jonathan Thomas
*/
#include "../include/ChunkWriter.h"
using namespace openshot;
ChunkWriter::ChunkWriter(FileReaderBase *reader, string path) throw (InvalidFile, InvalidFormat, InvalidCodec, InvalidOptions, OutOfMemory) :
path(path), cache_size(8), is_writing(false)
{
// Init FileInfo struct (clear all values)
InitFileInfo();
// Copy info struct from the source reader
CopyReaderInfo(reader);
}
// Add a frame to the queue waiting to be encoded.
void ChunkWriter::WriteFrame(tr1::shared_ptr<Frame> frame)
{
// Add frame pointer to "queue", waiting to be processed the next
// time the WriteFrames() method is called.
spooled_frames.push_back(frame);
// Write the frames once it reaches the correct cache size
if (spooled_frames.size() == cache_size)
{
// Is writer currently writing?
if (!is_writing)
// Write frames to video file
write_queued_frames();
else
{
// YES, WRITING... so wait until it finishes, before writing again
while (is_writing)
Sleep(1); // sleep for 250 milliseconds
// Write frames to video file
write_queued_frames();
}
}
// Keep track of the last frame added
last_frame = frame;
}
// Write all frames in the queue to the video file.
void ChunkWriter::write_queued_frames()
{
// Flip writing flag
is_writing = true;
// Transfer spool to queue
queued_frames = spooled_frames;
// Empty spool
spooled_frames.clear();
//omp_set_num_threads(1);
omp_set_nested(true);
#pragma omp parallel
{
#pragma omp single
{
// Loop through each queued image frame
while (!queued_frames.empty())
{
// Get front frame (from the queue)
tr1::shared_ptr<Frame> frame = queued_frames.front();
// Add to processed queue
processed_frames.push_back(frame);
// Encode and add the frame to the output file
process_frame(frame);
// Remove front item
queued_frames.pop_front();
} // end while
// Done writing
is_writing = false;
} // end omp single
} // end omp parallel
}
// Write a block of frames from a reader
void ChunkWriter::WriteFrame(FileReaderBase* reader, int start, int length)
{
// Loop through each frame (and encoded it)
for (int number = start; number <= length; number++)
{
// Get the frame
tr1::shared_ptr<Frame> f = reader->GetFrame(number);
// Encode frame
WriteFrame(f);
}
}
// Close the writer
void ChunkWriter::Close()
{
// Reset frame counters
write_video_count = 0;
write_audio_count = 0;
}
// process frame
void ChunkWriter::process_frame(tr1::shared_ptr<Frame> frame)
{
#pragma omp task firstprivate(frame)
{
// Determine the height & width of the source image
int source_image_width = frame->GetWidth();
int source_image_height = frame->GetHeight();
// Generate frame image name
stringstream thumb_name;
stringstream preview_name;
stringstream final_name;
thumb_name << frame->number << "_t.JPG";
preview_name << frame->number << "_p.JPG";
final_name << frame->number << "_f.JPG";
#pragma omp critical (chunk_output)
cout << "Writing " << thumb_name.str() << endl;
// Do nothing if size is 1x1 (i.e. no image in this frame)
if (source_image_height > 1 && source_image_width > 1)
{
// Write image of frame to chunk
frame->Save(thumb_name.str(), 0.25);
frame->Save(preview_name.str(), 0.5);
frame->Save(final_name.str(), 1.0);
}
} // end task
}

View File

@@ -30,6 +30,39 @@ void FileWriterBase::InitFileInfo()
info.audio_timebase = Fraction();
}
// This method copy's the info struct of a reader, and sets the writer with the same info
void FileWriterBase::CopyReaderInfo(FileReaderBase* reader)
{
info.has_video = reader->info.has_video;
info.has_audio = reader->info.has_audio;
info.duration = reader->info.duration;
info.file_size = reader->info.file_size;
info.height = reader->info.height;
info.width = reader->info.width;
info.pixel_format = reader->info.pixel_format;
info.fps.num = reader->info.fps.num;
info.fps.den = reader->info.fps.den;
info.video_bit_rate = reader->info.video_bit_rate;
info.pixel_ratio.num = reader->info.pixel_ratio.num;
info.pixel_ratio.den = reader->info.pixel_ratio.den;
info.display_ratio.num = reader->info.display_ratio.num;
info.display_ratio.den = reader->info.display_ratio.den;
info.vcodec = reader->info.vcodec;
info.video_length = reader->info.video_length;
info.video_stream_index = reader->info.video_stream_index;
info.video_timebase.num = reader->info.video_timebase.num;
info.video_timebase.den = reader->info.video_timebase.den;
info.interlaced_frame = reader->info.interlaced_frame;
info.top_field_first = reader->info.top_field_first;
info.acodec = reader->info.acodec;
info.audio_bit_rate = reader->info.audio_bit_rate;
info.sample_rate = reader->info.sample_rate;
info.channels = reader->info.channels;
info.audio_stream_index = reader->info.audio_stream_index;
info.audio_timebase.num = reader->info.audio_timebase.num;
info.audio_timebase.den = reader->info.audio_timebase.den;
}
// Display file information
void FileWriterBase::DisplayInfo() {
cout << fixed << setprecision(2) << boolalpha;

View File

@@ -18,6 +18,16 @@ void FrameReady(int number)
int main()
{
// Chunk writer example
FFmpegReader *r1 = new FFmpegReader("/home/jonathan/Videos/sintel_trailer-720p.mp4");
r1->Open();
ChunkWriter cw(r1, "");
cw.WriteFrame(r1, 1, 600);
return 0;
TextReader r(720, 480, 10, 10, GRAVITY_TOP_RIGHT, "What's Up!", "Courier", 30, "Blue", "Black");
r.Open();
tr1::shared_ptr<Frame> f = r.GetFrame(1);

View File

@@ -21,6 +21,7 @@
#include "../include/FileWriterBase.h"
#include "../include/Cache.h"
#include "../include/Clip.h"
#include "../include/ChunkWriter.h"
#include "../include/Coordinate.h"
#include "../include/DummyReader.h"
#include "../include/Exceptions.h"
@@ -48,6 +49,7 @@
%include "../include/FileReaderBase.h"
%include "../include/FileWriterBase.h"
%include "../include/Cache.h"
%include "../include/ChunkWriter.h"
%include "../include/Clip.h"
%include "../include/Coordinate.h"
#ifdef USE_BLACKMAGIC