/**
* \file
* \brief Source code for the ChunkWriter class
* \author Copyright (c) 2013 Jonathan Thomas
*/
#include "../include/ChunkWriter.h"
using namespace openshot;
ChunkWriter::ChunkWriter(string path, FileReaderBase *reader) throw (InvalidFile, InvalidFormat, InvalidCodec, InvalidOptions, OutOfMemory) :
local_reader(reader), path(path), cache_size(8), is_writing(false)
{
// Init FileInfo struct (clear all values)
InitFileInfo();
// Copy info struct from the source reader
CopyReaderInfo(local_reader);
// Create folder (if it does not exist)
create_folder(path);
// Write JSON meta data file
write_json_meta_data();
}
// Add a frame to the queue waiting to be encoded.
void ChunkWriter::WriteFrame(tr1::shared_ptr 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 = 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 f = reader->GetFrame(number);
// Encode frame
WriteFrame(f);
}
}
// Write a block of frames from the local cached reader
void ChunkWriter::WriteFrame(int start, int length)
{
// Loop through each frame (and encoded it)
for (int number = start; number <= length; number++)
{
// Get the frame
tr1::shared_ptr f = local_reader->GetFrame(number);
// Encode frame
WriteFrame(f);
}
}
// Close the writer
void ChunkWriter::Close()
{
// Reset frame counters
write_video_count = 0;
write_audio_count = 0;
}
// write json meta data
void ChunkWriter::write_json_meta_data()
{
Json::Value root;
root["has_video"] = local_reader->info.has_video;
root["has_audio"] = local_reader->info.has_audio;
root["duration"] = local_reader->info.duration;
stringstream filesize_stream;
filesize_stream << local_reader->info.file_size;
root["file_size"] = filesize_stream.str();
root["height"] = local_reader->info.height;
root["width"] = local_reader->info.width;
root["pixel_format"] = local_reader->info.pixel_format;
root["fps"] = Json::Value(Json::objectValue);
root["fps"]["num"] = local_reader->info.fps.num;
root["fps"]["den"] = local_reader->info.fps.den;
root["video_bit_rate"] = local_reader->info.video_bit_rate;
root["pixel_ratio"] = Json::Value(Json::objectValue);
root["pixel_ratio"]["num"] = local_reader->info.pixel_ratio.num;
root["pixel_ratio"]["den"] = local_reader->info.pixel_ratio.den;
root["display_ratio"] = Json::Value(Json::objectValue);
root["display_ratio"]["num"] = local_reader->info.display_ratio.num;
root["display_ratio"]["den"] = local_reader->info.display_ratio.den;
root["vcodec"] = local_reader->info.vcodec;
stringstream video_length_stream;
video_length_stream << local_reader->info.video_length;
root["video_length"] = video_length_stream.str();
root["video_stream_index"] = local_reader->info.video_stream_index;
root["video_timebase"] = Json::Value(Json::objectValue);
root["video_timebase"]["num"] = local_reader->info.video_timebase.num;
root["video_timebase"]["den"] = local_reader->info.video_timebase.den;
root["interlaced_frame"] = local_reader->info.interlaced_frame;
root["top_field_first"] = local_reader->info.top_field_first;
root["acodec"] = local_reader->info.acodec;
root["audio_bit_rate"] = local_reader->info.audio_bit_rate;
root["sample_rate"] = local_reader->info.sample_rate;
root["channels"] = local_reader->info.channels;
root["audio_stream_index"] = local_reader->info.audio_stream_index;
root["audio_timebase"] = Json::Value(Json::objectValue);
root["audio_timebase"]["num"] = local_reader->info.audio_timebase.num;
root["audio_timebase"]["den"] = local_reader->info.audio_timebase.den;
cout << root << endl;
}
// check for chunk folder
bool ChunkWriter::create_folder(string path)
{
QDir dir(path.c_str());
if (!dir.exists()) {
dir.mkpath(".");
}
}
// check for valid chunk json
bool ChunkWriter::is_chunk_valid()
{
}
// process frame
void ChunkWriter::process_frame(tr1::shared_ptr 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
}