Support encoding of MPEG2 DCPs.
[dcpomatic.git] / src / lib / reel_writer.cc
index 201c23e71763d40fe9e70992b6b7a6984450a436..8dc0d7f06ff9936530c0520458ecd08977f38cf8 100644 (file)
@@ -146,30 +146,45 @@ ReelWriter::ReelWriter (
                        dcp::filesystem::rename(asset.string() + ".tmp", asset);
                }
 
+               auto const rate = dcp::Fraction(film()->video_frame_rate(), 1);
 
-               if (film()->three_d()) {
-                       _picture_asset = std::make_shared<dcp::StereoJ2KPictureAsset>(dcp::Fraction(film()->video_frame_rate(), 1), standard);
-               } else {
-                       _picture_asset = std::make_shared<dcp::MonoJ2KPictureAsset>(dcp::Fraction(film()->video_frame_rate(), 1), standard);
-               }
+               auto setup = [this](shared_ptr<dcp::PictureAsset> asset) {
+                       asset->set_size(film()->frame_size());
+                       asset->set_metadata(mxf_metadata());
 
-               _picture_asset->set_size (film()->frame_size());
-               _picture_asset->set_metadata (mxf_metadata());
+                       if (film()->encrypted()) {
+                               asset->set_key(film()->key());
+                               asset->set_context_id(film()->context_id());
+                       }
+               };
 
-               if (film()->encrypted()) {
-                       _picture_asset->set_key (film()->key());
-                       _picture_asset->set_context_id (film()->context_id());
+               if (film()->video_encoding() == VideoEncoding::JPEG2000) {
+                       if (film()->three_d()) {
+                               _j2k_picture_asset = std::make_shared<dcp::StereoJ2KPictureAsset>(rate, standard);
+                       } else {
+                               _j2k_picture_asset = std::make_shared<dcp::MonoJ2KPictureAsset>(rate, standard);
+                       }
+                       setup(_j2k_picture_asset);
+                       _j2k_picture_asset->set_file(asset);
+                       _j2k_picture_asset_writer = _j2k_picture_asset->start_write(asset, _first_nonexistent_frame > 0 ? dcp::Behaviour::OVERWRITE_EXISTING : dcp::Behaviour::MAKE_NEW);
+               } else {
+                       _mpeg2_picture_asset = std::make_shared<dcp::MonoMPEG2PictureAsset>(rate);
+                       setup(_mpeg2_picture_asset);
+                       _mpeg2_picture_asset->set_file(asset);
+                       _mpeg2_picture_asset_writer = _mpeg2_picture_asset->start_write(asset, _first_nonexistent_frame > 0 ? dcp::Behaviour::OVERWRITE_EXISTING : dcp::Behaviour::MAKE_NEW);
                }
 
-               _picture_asset->set_file (asset);
-               _picture_asset_writer = _picture_asset->start_write(asset, _first_nonexistent_frame > 0 ? dcp::Behaviour::OVERWRITE_EXISTING : dcp::Behaviour::MAKE_NEW);
        } else if (!text_only) {
                /* We already have a complete picture asset that we can just re-use */
                /* XXX: what about if the encryption key changes? */
-               if (film()->three_d()) {
-                       _picture_asset = make_shared<dcp::StereoJ2KPictureAsset>(asset);
+               if (film()->video_encoding() == VideoEncoding::JPEG2000) {
+                       if (film()->three_d()) {
+                               _j2k_picture_asset = make_shared<dcp::StereoJ2KPictureAsset>(asset);
+                       } else {
+                               _j2k_picture_asset = make_shared<dcp::MonoJ2KPictureAsset>(asset);
+                       }
                } else {
-                       _picture_asset = make_shared<dcp::MonoJ2KPictureAsset>(asset);
+                       _mpeg2_picture_asset = make_shared<dcp::MonoMPEG2PictureAsset>(asset);
                }
        }
 
@@ -272,7 +287,7 @@ ReelWriter::check_existing_picture_asset (boost::filesystem::path asset)
 void
 ReelWriter::write (shared_ptr<const Data> encoded, Frame frame, Eyes eyes)
 {
-       if (!_picture_asset_writer) {
+       if (!_j2k_picture_asset_writer) {
                /* We're not writing any data */
                return;
        }
@@ -300,21 +315,28 @@ ReelWriter::write (shared_ptr<const dcp::AtmosFrame> atmos, AtmosMetadata metada
 
 
 void
-ReelWriter::fake_write (int size)
+ReelWriter::write(shared_ptr<dcp::MonoMPEG2PictureFrame> image)
+{
+       _mpeg2_picture_asset_writer->write(image->data(), image->size());
+}
+
+
+void
+ReelWriter::fake_write(dcp::J2KFrameInfo const& info)
 {
-       if (!_picture_asset_writer) {
+       if (!_j2k_picture_asset_writer) {
                /* We're not writing any data */
                return;
        }
 
-       _picture_asset_writer->fake_write (size);
+       _j2k_picture_asset_writer->fake_write(info);
 }
 
 
 void
 ReelWriter::repeat_write (Frame frame, Eyes eyes)
 {
-       if (!_picture_asset_writer) {
+       if (!_j2k_picture_asset_writer) {
                /* We're not writing any data */
                return;
        }
@@ -327,10 +349,16 @@ ReelWriter::repeat_write (Frame frame, Eyes eyes)
 void
 ReelWriter::finish (boost::filesystem::path output_dcp)
 {
-       if (_picture_asset_writer && !_picture_asset_writer->finalize ()) {
-               /* Nothing was written to the picture asset */
-               LOG_GENERAL ("Nothing was written to reel %1 of %2", _reel_index, _reel_count);
-               _picture_asset.reset ();
+       if (_j2k_picture_asset_writer && !_j2k_picture_asset_writer->finalize()) {
+               /* Nothing was written to the J2K picture asset */
+               LOG_GENERAL("Nothing was written to J2K asset for reel %1 of %2", _reel_index, _reel_count);
+               _j2k_picture_asset.reset();
+       }
+
+       if (_mpeg2_picture_asset_writer && !_mpeg2_picture_asset_writer->finalize()) {
+               /* Nothing was written to the MPEG2 picture asset */
+               LOG_GENERAL("Nothing was written to MPEG2 asset for reel %1 of %2", _reel_index, _reel_count);
+               _mpeg2_picture_asset.reset();
        }
 
        if (_sound_asset_writer && !_sound_asset_writer->finalize ()) {
@@ -338,12 +366,21 @@ ReelWriter::finish (boost::filesystem::path output_dcp)
                _sound_asset.reset ();
        }
 
+       shared_ptr<dcp::PictureAsset> picture_asset;
+       if (_j2k_picture_asset) {
+               picture_asset = _j2k_picture_asset;
+       } else if (_mpeg2_picture_asset) {
+               picture_asset = _mpeg2_picture_asset;
+       }
+
        /* Hard-link any video asset file into the DCP */
-       if (_picture_asset) {
-               DCPOMATIC_ASSERT (_picture_asset->file());
-               boost::filesystem::path video_from = _picture_asset->file().get();
-               boost::filesystem::path video_to = output_dcp;
-               video_to /= video_asset_filename (_picture_asset, _reel_index, _reel_count, _content_summary);
+       if (picture_asset) {
+               auto const file = picture_asset->file();
+               DCPOMATIC_ASSERT(file);
+
+               auto video_from = *file;
+               auto video_to = output_dcp;
+               video_to /= video_asset_filename(picture_asset, _reel_index, _reel_count, _content_summary);
                /* There may be an existing "to" file if we are recreating a DCP in the same place without
                   changing any video.
                */
@@ -371,7 +408,7 @@ ReelWriter::finish (boost::filesystem::path output_dcp)
                        }
                }
 
-               _picture_asset->set_file (video_to);
+               picture_asset->set_file(video_to);
        }
 
        /* Move the audio asset into the DCP */
@@ -495,17 +532,17 @@ ReelWriter::create_reel_picture (shared_ptr<dcp::Reel> reel, list<ReferencedReel
 {
        shared_ptr<dcp::ReelPictureAsset> reel_asset;
 
-       if (_picture_asset) {
+       if (_j2k_picture_asset) {
                /* We have made a picture asset of our own.  Put it into the reel */
-               auto mono = dynamic_pointer_cast<dcp::MonoJ2KPictureAsset>(_picture_asset);
-               if (mono) {
+               if (auto mono = dynamic_pointer_cast<dcp::MonoJ2KPictureAsset>(_j2k_picture_asset)) {
                        reel_asset = make_shared<dcp::ReelMonoPictureAsset>(mono, 0);
                }
 
-               auto stereo = dynamic_pointer_cast<dcp::StereoJ2KPictureAsset>(_picture_asset);
-               if (stereo) {
+               if (auto stereo = dynamic_pointer_cast<dcp::StereoJ2KPictureAsset>(_j2k_picture_asset)) {
                        reel_asset = make_shared<dcp::ReelStereoPictureAsset>(stereo, 0);
                }
+       } else if (_mpeg2_picture_asset) {
+               reel_asset = make_shared<dcp::ReelMonoPictureAsset>(_mpeg2_picture_asset, 0);
        } else {
                LOG_GENERAL ("no picture asset of our own; look through %1", refs.size());
                /* We don't have a picture asset of our own; hopefully we have one to reference */
@@ -734,8 +771,11 @@ try
 {
        vector<shared_ptr<const dcp::Asset>> assets;
 
-       if (_picture_asset) {
-               assets.push_back(_picture_asset);
+       if (_j2k_picture_asset) {
+               assets.push_back(_j2k_picture_asset);
+       }
+       if (_mpeg2_picture_asset) {
+               assets.push_back(_mpeg2_picture_asset);
        }
        if (_sound_asset) {
                assets.push_back(_sound_asset);