MXFAsset::MXFAsset (string directory, string file_name)
: Asset (directory, file_name)
, _progress (0)
- , _fps (0)
+ , _edit_rate (0)
, _entry_point (0)
, _intrinsic_duration (0)
, _duration (0)
}
-MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal<void (float)>* progress, int fps, int intrinsic_duration)
+MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal<void (float)>* progress, int edit_rate, int intrinsic_duration)
: Asset (directory, file_name)
, _progress (progress)
- , _fps (fps)
+ , _edit_rate (edit_rate)
, _entry_point (0)
, _intrinsic_duration (intrinsic_duration)
, _duration (intrinsic_duration)
{
}
-
-void
-MXFAsset::set_entry_point (int e)
-{
- _entry_point = e;
-}
-
-void
-MXFAsset::set_duration (int d)
-{
- _duration = d;
-}
-
void
MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid)
{
return false;
}
- if (_fps != other_mxf->_fps) {
- notes.push_back ("MXF frames per second differ");
+ if (_edit_rate != other_mxf->_edit_rate) {
+ notes.push_back ("MXF edit rates differ");
return false;
}
return true;
}
-
-int
-MXFAsset::intrinsic_duration () const
-{
- return _intrinsic_duration;
-}
class MXFAsset : public Asset
{
public:
+ /** Construct an MXFAsset.
+ * This class will not write anything to disk in this constructor, but subclasses may.
+ *
+ * @param directory Directory where MXF file is.
+ * @param file_name Name of MXF file.
+ */
MXFAsset (std::string directory, std::string file_name);
/** Construct an MXFAsset.
+ * This class will not write anything to disk in this constructor, but subclasses may.
+ *
* @param directory Directory where MXF file is.
* @param file_name Name of MXF file.
- * @param progress Signal to inform of progress.
- * @param fps Frames per second.
+ * @param progress Signal to use to inform of progress, or 0.
+ * @param edit_rate Edit rate in frames per second (usually equal to the video frame rate).
* @param intrinsic_duration Duration of the whole asset in frames.
*/
- MXFAsset (std::string directory, std::string file_name, boost::signals2::signal<void (float)>* progress, int fps, int intrinsic_duration);
+ MXFAsset (std::string directory, std::string file_name, boost::signals2::signal<void (float)>* progress, int edit_rate, int intrinsic_duration);
- void set_entry_point (int e);
- void set_duration (int d);
-
- virtual bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, std::list<std::string>& notes) const;
+ void set_entry_point (int e) {
+ _entry_point = e;
+ }
- int intrinsic_duration () const;
- int frames_per_second () const {
- return _fps;
+ void set_duration (int d) {
+ _duration = d;
}
void set_intrinsic_duration (int d) {
_intrinsic_duration = d;
}
+ virtual bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, std::list<std::string>& notes) const;
+
+ int intrinsic_duration () const {
+ return _intrinsic_duration;
+ }
+
+ int edit_rate () const {
+ return _edit_rate;
+ }
+
/** Fill in a ADSCP::WriteInfo struct.
* @param w struct to fill in.
* @param uuid uuid to use.
protected:
- /** Signal to emit to report progress */
+ /** Signal to emit to report progress, or 0 */
boost::signals2::signal<void (float)>* _progress;
- /** Frames per second */
- int _fps;
+ /** The edit rate; this is normally equal to the number of video frames per second */
+ int _edit_rate;
/** Start point to present in frames */
int _entry_point;
/** Total length in frames */
s << " <MainPicture>\n"
<< " <Id>urn:uuid:" << _uuid << "</Id>\n"
<< " <AnnotationText>" << _file_name << "</AnnotationText>\n"
- << " <EditRate>" << _fps << " 1</EditRate>\n"
+ << " <EditRate>" << _edit_rate << " 1</EditRate>\n"
<< " <IntrinsicDuration>" << _intrinsic_duration << "</IntrinsicDuration>\n"
<< " <EntryPoint>" << _entry_point << "</EntryPoint>\n"
<< " <Duration>" << _duration << "</Duration>\n"
- << " <FrameRate>" << _fps << " 1</FrameRate>\n"
+ << " <FrameRate>" << _edit_rate << " 1</FrameRate>\n"
<< " <ScreenAspectRatio>" << _size.width << " " << _size.height << "</ScreenAspectRatio>\n"
<< " </MainPicture>\n";
}
_size.width = desc.StoredWidth;
_size.height = desc.StoredHeight;
- _fps = desc.EditRate.Numerator;
+ _edit_rate = desc.EditRate.Numerator;
assert (desc.EditRate.Denominator == 1);
_intrinsic_duration = desc.ContainerDuration;
}
ASDCP::JP2K::PictureDescriptor picture_desc;
j2k_parser.FillPictureDescriptor (picture_desc);
- picture_desc.EditRate = ASDCP::Rational (_fps, 1);
+ picture_desc.EditRate = ASDCP::Rational (_edit_rate, 1);
ASDCP::WriterInfo writer_info;
fill_writer_info (&writer_info, _uuid);
return shared_ptr<MonoPictureAssetWriter> (new MonoPictureAssetWriter (this));
}
+/** @param a Asset to write to. `a' must not be deleted while
+ * this writer class still exists, or bad things will happen.
+ */
MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a)
: _frame_buffer (4 * Kumu::Megabyte)
, _asset (a)
void
MonoPictureAssetWriter::write (uint8_t* data, int size)
{
+ assert (!_finalized);
+
if (ASDCP_FAILURE (_j2k_parser.OpenReadFrame (data, size, _frame_buffer))) {
throw MiscError ("could not parse J2K frame");
}
if (_frames_written == 0) {
+ /* This is our first frame; set up the writer */
+
_j2k_parser.FillPictureDescriptor (_picture_descriptor);
- _picture_descriptor.EditRate = ASDCP::Rational (_asset->frames_per_second(), 1);
+ _picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1);
MXFAsset::fill_writer_info (&_writer_info, _asset->uuid());
class PictureAsset : public MXFAsset
{
public:
+ /** Construct a PictureAsset.
+ * This class will not write anything to disk in this constructor, but subclasses may.
+ *
+ * @param directory Directory where MXF file is.
+ * @param mxf_name Name of MXF file.
+ */
PictureAsset (std::string directory, std::string mxf_name);
+
+ /** Construct a PictureAsset.
+ * This class will not write anything to disk in this constructor, but subclasses may.
+ *
+ * @param directory Directory where MXF file is.
+ * @param mxf_name Name of MXF file.
+ * @param progress Signal to use to inform of progres, or 0.
+ * @param fps Video Frames per second.
+ * @param intrinsic_duration Duration of all the frames in the asset.
+ * @param size Size of video frame images in pixels.
+ */
PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal<void (float)>* progress, int fps, int intrinsic_duration, Size size);
/** Write details of this asset to a CPL stream.
class MonoPictureAsset;
+/** A helper class for writing to MonoPictureAssets progressively (i.e. writing frame-by-frame,
+ * rather than giving libdcp all the frames in one go).
+ *
+ * Objects of this class can only be created with MonoPictureAsset::start_write().
+ *
+ * Frames can be written to the MonoPictureAsset by calling write() with a JPEG2000 image
+ * (a verbatim .j2 file). finalize() must be called after the last frame has been written.
+ * The action of finalize() can't be done in MonoPictureAssetWriter's destructor as it may
+ * throw an exception.
+ */
class MonoPictureAssetWriter
{
public:
ASDCP::WriterInfo _writer_info;
ASDCP::JP2K::PictureDescriptor _picture_descriptor;
MonoPictureAsset* _asset;
+ /** Number of picture frames written to the asset so far */
int _frames_written;
+ /** true if finalize() has been called */
bool _finalized;
};
class MonoPictureAsset : public PictureAsset
{
public:
- /** Construct a PictureAsset, generating the MXF from the JPEG2000 files.
+ /** Construct a MonoPictureAsset, generating the MXF from the JPEG2000 files.
* This may take some time; progress is indicated by emission of the Progress signal.
+ *
* @param files Pathnames of JPEG2000 files, in frame order.
* @param directory Directory in which to create MXF file.
* @param mxf_name Name of MXF file to create.
* @param progress Signal to inform of progress.
- * @param fps Frames per second.
+ * @param fps Video frames per second.
* @param intrinsic_duration Length of the whole asset in frames.
* @param size Size of images in pixels.
*/
Size size
);
- /** Construct a PictureAsset, generating the MXF from the JPEG2000 files.
+ /** Construct a MonoPictureAsset, generating the MXF from the JPEG2000 files.
* This may take some time; progress is indicated by emission of the Progress signal.
+ *
* @param get_path Functor which returns a JPEG2000 file path for a given frame (frames counted from 0).
* @param directory Directory in which to create MXF file.
* @param mxf_name Name of MXF file to create.
* @param progress Signal to inform of progress.
- * @param fps Frames per second.
+ * @param fps Video frames per second.
* @param intrinsic_duration Length of the whole asset in frames.
* @param size Size of images in pixels.
*/
Size size
);
+ /** Construct a MonoPictureAsset, reading the MXF from disk.
+ * @param directory Directory that the MXF is in.
+ * @param mxf_name The filename of the MXF within `directory'.
+ */
MonoPictureAsset (std::string directory, std::string mxf_name);
-
+
+ /** Construct a MonoPictureAsset for progressive writing using
+ * start_write() and a MonoPictureAssetWriter.
+ *
+ * @param directory Directory to put the MXF in.
+ * @param mxf_name Filename of the MXF within this directory.
+ * @param fps Video frames per second.
+ * @param size Size in pixels that the picture frames will be.
+ */
MonoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size);
+ /** Start a progressive write to a MonoPictureAsset */
boost::shared_ptr<MonoPictureAssetWriter> start_write ();
boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
_sampling_rate = desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator;
_channels = desc.ChannelCount;
- _fps = desc.EditRate.Numerator;
+ _edit_rate = desc.EditRate.Numerator;
assert (desc.EditRate.Denominator == 1);
_intrinsic_duration = desc.ContainerDuration;
}
void
SoundAsset::construct (boost::function<string (Channel)> get_path)
{
- ASDCP::Rational asdcp_fps (_fps, 1);
+ ASDCP::Rational asdcp_edit_rate (_edit_rate, 1);
ASDCP::PCM::WAVParser pcm_parser_channel[_channels];
- if (pcm_parser_channel[0].OpenRead (get_path(LEFT).c_str(), asdcp_fps)) {
+ if (pcm_parser_channel[0].OpenRead (get_path(LEFT).c_str(), asdcp_edit_rate)) {
throw FileError ("could not open WAV file for reading", get_path(LEFT));
}
pcm_parser_channel[0].FillAudioDescriptor (audio_desc);
audio_desc.ChannelCount = 0;
audio_desc.BlockAlign = 0;
- audio_desc.EditRate = asdcp_fps;
+ audio_desc.EditRate = asdcp_edit_rate;
audio_desc.AvgBps = audio_desc.AvgBps * _channels;
Channel channels[] = {
string const path = get_path (channels[i]);
- if (ASDCP_FAILURE (pcm_parser_channel[i].OpenRead (path.c_str(), asdcp_fps))) {
+ if (ASDCP_FAILURE (pcm_parser_channel[i].OpenRead (path.c_str(), asdcp_edit_rate))) {
throw FileError ("could not open WAV file for reading", path);
}
s << " <MainSound>\n"
<< " <Id>urn:uuid:" << _uuid << "</Id>\n"
<< " <AnnotationText>" << _file_name << "</AnnotationText>\n"
- << " <EditRate>" << _fps << " 1</EditRate>\n"
+ << " <EditRate>" << _edit_rate << " 1</EditRate>\n"
<< " <IntrinsicDuration>" << _intrinsic_duration << "</IntrinsicDuration>\n"
<< " <EntryPoint>" << _entry_point << "</EntryPoint>\n"
<< " <Duration>" << _duration << "</Duration>\n"
, _frame_buffer_offset (0)
{
/* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
- _audio_desc.EditRate = ASDCP::Rational (_asset->frames_per_second(), 1);
+ _audio_desc.EditRate = ASDCP::Rational (_asset->edit_rate(), 1);
_audio_desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 0);
_audio_desc.Locked = 0;
_audio_desc.ChannelCount = _asset->channels ();