summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2023-11-14 22:01:07 +0100
committerCarl Hetherington <cth@carlh.net>2024-04-22 01:42:00 +0200
commit066471f69400fc72e9c126ab36f5427329f30220 (patch)
treedd15f6b6aa7a74b5cca2ce5f300723b1b72d2f11 /src
parent0fbfe3d2dd5de9eab299f2ff569bff29cc6f8e19 (diff)
Support MPEG2 decompression.
Diffstat (limited to 'src')
-rw-r--r--src/asset_factory.cc4
-rw-r--r--src/asset_reader.h1
-rw-r--r--src/dcp.cc2
-rw-r--r--src/exceptions.h18
-rw-r--r--src/ffmpeg_image.h86
-rw-r--r--src/mono_mpeg2_picture_asset.cc77
-rw-r--r--src/mono_mpeg2_picture_asset.h64
-rw-r--r--src/mono_mpeg2_picture_asset_reader.h58
-rw-r--r--src/mono_mpeg2_picture_frame.cc83
-rw-r--r--src/mono_mpeg2_picture_frame.h76
-rw-r--r--src/mpeg2_picture_asset.cc74
-rw-r--r--src/mpeg2_picture_asset.h77
-rw-r--r--src/mpeg2_transcode.cc143
-rw-r--r--src/mpeg2_transcode.h89
-rw-r--r--src/reel.cc2
-rw-r--r--src/reel_mono_picture_asset.cc2
-rw-r--r--src/reel_mono_picture_asset.h19
-rw-r--r--src/reel_picture_asset.cc2
-rw-r--r--src/reel_picture_asset.h32
-rw-r--r--src/wscript14
20 files changed, 908 insertions, 15 deletions
diff --git a/src/asset_factory.cc b/src/asset_factory.cc
index 240b7685..26811366 100644
--- a/src/asset_factory.cc
+++ b/src/asset_factory.cc
@@ -41,6 +41,7 @@
#include "atmos_asset.h"
#include "compose.hpp"
#include "mono_j2k_picture_asset.h"
+#include "mono_mpeg2_picture_asset.h"
#include "smpte_subtitle_asset.h"
#include "sound_asset.h"
#include "stereo_j2k_picture_asset.h"
@@ -68,8 +69,9 @@ dcp::asset_factory (boost::filesystem::path path, bool ignore_incorrect_picture_
}
switch (type) {
case ASDCP::ESS_UNKNOWN:
+ throw ReadError("Unknown asset type");
case ASDCP::ESS_MPEG2_VES:
- throw ReadError ("MPEG2 video essences are not supported");
+ return make_shared<MonoMPEG2PictureAsset>(path);
case ASDCP::ESS_JPEG_2000:
try {
return make_shared<MonoJ2KPictureAsset>(path);
diff --git a/src/asset_reader.h b/src/asset_reader.h
index 3bf9b8b9..091ac915 100644
--- a/src/asset_reader.h
+++ b/src/asset_reader.h
@@ -91,6 +91,7 @@ protected:
private:
friend class AtmosAsset;
friend class MonoJ2KPictureAsset;
+ friend class MonoMPEG2PictureAsset;
friend class SoundAsset;
friend class StereoJ2KPictureAsset;
diff --git a/src/dcp.cc b/src/dcp.cc
index 816fc178..f0379202 100644
--- a/src/dcp.cc
+++ b/src/dcp.cc
@@ -52,6 +52,7 @@
#include "interop_subtitle_asset.h"
#include "metadata.h"
#include "mono_j2k_picture_asset.h"
+#include "mono_mpeg2_picture_asset.h"
#include "j2k_picture_asset.h"
#include "pkl.h"
#include "raw_convert.h"
@@ -247,6 +248,7 @@ DCP::read (vector<dcp::VerificationNote>* notes, bool ignore_incorrect_picture_m
}
} else if (
*pkl_type == remove_parameters(J2KPictureAsset::static_pkl_type(standard)) ||
+ *pkl_type == remove_parameters(MPEG2PictureAsset::static_pkl_type(standard)) ||
*pkl_type == remove_parameters(SoundAsset::static_pkl_type(standard)) ||
*pkl_type == remove_parameters(AtmosAsset::static_pkl_type(standard)) ||
*pkl_type == remove_parameters(SMPTESubtitleAsset::static_pkl_type(standard))
diff --git a/src/exceptions.h b/src/exceptions.h
index 8d85f02a..88ec253c 100644
--- a/src/exceptions.h
+++ b/src/exceptions.h
@@ -140,6 +140,24 @@ public:
};
+class MPEG2CodecError : public MiscError
+{
+public:
+ explicit MPEG2CodecError(std::string message)
+ : MiscError(message)
+ {}
+};
+
+
+class MPEG2DecompressionError : public ReadError
+{
+public:
+ explicit MPEG2DecompressionError(std::string message)
+ : ReadError(message)
+ {}
+};
+
+
class BadContentKindError : public ReadError
{
public:
diff --git a/src/ffmpeg_image.h b/src/ffmpeg_image.h
new file mode 100644
index 00000000..56b68574
--- /dev/null
+++ b/src/ffmpeg_image.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_FFMPEG_IMAGE_H
+#define LIBDCP_FFMPEG_IMAGE_H
+
+
+extern "C" {
+#include <libavutil/frame.h>
+}
+#include <algorithm>
+#include <vector>
+
+
+namespace dcp {
+
+
+class FFmpegImage
+{
+public:
+ explicit FFmpegImage(AVFrame* frame)
+ : _frame(frame)
+ {}
+
+ FFmpegImage(FFmpegImage const& other) = delete;
+ FFmpegImage& operator=(FFmpegImage const& other) = delete;
+
+ FFmpegImage(FFmpegImage&& other) {
+ std::swap(_frame, other._frame);
+ }
+
+ FFmpegImage& operator=(FFmpegImage&& other) {
+ std::swap(_frame, other._frame);
+ return *this;
+ }
+
+ ~FFmpegImage()
+ {
+ av_frame_free(&_frame);
+ }
+
+ AVFrame const * frame() const {
+ return _frame;
+ }
+
+private:
+ AVFrame* _frame = nullptr;
+};
+
+
+}
+
+
+#endif
+
diff --git a/src/mono_mpeg2_picture_asset.cc b/src/mono_mpeg2_picture_asset.cc
new file mode 100644
index 00000000..548e936a
--- /dev/null
+++ b/src/mono_mpeg2_picture_asset.cc
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "filesystem.h"
+#include "mono_mpeg2_picture_asset.h"
+#include "mono_mpeg2_picture_asset_reader.h"
+#include <asdcp/AS_DCP.h>
+
+
+using std::shared_ptr;
+using namespace dcp;
+
+
+MonoMPEG2PictureAsset::MonoMPEG2PictureAsset(boost::filesystem::path file)
+ : MPEG2PictureAsset(file)
+{
+ Kumu::FileReaderFactory factory;
+ ASDCP::MPEG2::MXFReader reader(factory);
+ auto const result = reader.OpenRead(dcp::filesystem::fix_long_path(file).string().c_str());
+ if (ASDCP_FAILURE(result)) {
+ boost::throw_exception(MXFFileError("could not open MXF file for reading", file.string(), result));
+ }
+
+ ASDCP::MPEG2::VideoDescriptor desc;
+ if (ASDCP_FAILURE(reader.FillVideoDescriptor(desc))) {
+ boost::throw_exception(ReadError("could not read video MXF information"));
+ }
+
+ read_video_descriptor(desc);
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE(reader.FillWriterInfo(info))) {
+ boost::throw_exception(ReadError("could not read video MXF information"));
+ }
+
+ _id = read_writer_info(info);
+}
+
+
+shared_ptr<MonoMPEG2PictureAssetReader>
+MonoMPEG2PictureAsset::start_read () const
+{
+ /* Can't use make_shared here as the MonoMPEG2PictureAssetReader constructor is private */
+ return shared_ptr<MonoMPEG2PictureAssetReader>(new MonoMPEG2PictureAssetReader(this, key(), standard()));
+
+}
diff --git a/src/mono_mpeg2_picture_asset.h b/src/mono_mpeg2_picture_asset.h
new file mode 100644
index 00000000..a740cc6c
--- /dev/null
+++ b/src/mono_mpeg2_picture_asset.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_MONO_MPEG2_PICTURE_ASSET_H
+#define LIBDCP_MONO_MPEG2_PICTURE_ASSET_H
+
+
+/** @file src/mono_mpeg2_picture_asset.h
+ * @brief MonoMPEG2PictureAsset class
+ */
+
+
+#include "mpeg2_picture_asset.h"
+#include "mono_mpeg2_picture_asset_reader.h"
+
+
+namespace dcp {
+
+
+class MonoMPEG2PictureAsset : public MPEG2PictureAsset
+{
+public:
+ explicit MonoMPEG2PictureAsset(boost::filesystem::path file);
+
+ std::shared_ptr<MonoMPEG2PictureAssetReader> start_read() const;
+};
+
+
+
+}
+
+
+#endif
diff --git a/src/mono_mpeg2_picture_asset_reader.h b/src/mono_mpeg2_picture_asset_reader.h
new file mode 100644
index 00000000..75155f40
--- /dev/null
+++ b/src/mono_mpeg2_picture_asset_reader.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+/** @file src/mono_mpeg2_picture_asset_reader.h
+ * @brief MonoJ2KPictureAssetReader typedef
+ */
+
+
+#ifndef LIBDCP_MONO_MPEG2_PICTURE_ASSET_READER_H
+#define LIBDCP_MONO_MPEG2_PICTURE_ASSET_READER_H
+
+
+#include "asset_reader.h"
+#include "mono_mpeg2_picture_frame.h"
+
+
+namespace dcp {
+
+
+typedef AssetReader<ASDCP::MPEG2::MXFReader, MonoMPEG2PictureFrame> MonoMPEG2PictureAssetReader;
+
+
+}
+
+
+#endif
+
diff --git a/src/mono_mpeg2_picture_frame.cc b/src/mono_mpeg2_picture_frame.cc
new file mode 100644
index 00000000..3da67212
--- /dev/null
+++ b/src/mono_mpeg2_picture_frame.cc
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "compose.hpp"
+#include "mono_mpeg2_picture_frame.h"
+
+
+using std::make_shared;
+using std::shared_ptr;
+using namespace dcp;
+
+
+
+/** Make a picture frame from a 2D (monoscopic) asset.
+ * @param reader Reader for the asset's MXF file.
+ * @param n Frame within the asset, not taking EntryPoint into account.
+ * @param c Context for decryption, or 0.
+ * @param check_hmac true to check the HMAC and give an error if it is not as expected.
+ */
+MonoMPEG2PictureFrame::MonoMPEG2PictureFrame(ASDCP::MPEG2::MXFReader* reader, int n, shared_ptr<DecryptionContext> context, bool check_hmac)
+{
+ /* XXX: unfortunate guesswork on this buffer size */
+ _buffer = make_shared<ASDCP::MPEG2::FrameBuffer>(4 * Kumu::Megabyte);
+
+ auto const r = reader->ReadFrame(n, *_buffer, context->context(), check_hmac ? context->hmac() : nullptr);
+
+ if (ASDCP_FAILURE(r)) {
+ boost::throw_exception(ReadError(String::compose("could not read video frame %1 (%2)", n, static_cast<int>(r))));
+ }
+}
+
+
+uint8_t const *
+MonoMPEG2PictureFrame::data() const
+{
+ return _buffer->RoData();
+}
+
+
+uint8_t *
+MonoMPEG2PictureFrame::data()
+{
+ return _buffer->Data();
+}
+
+
+int
+MonoMPEG2PictureFrame::size() const
+{
+ return _buffer->Size();
+}
+
diff --git a/src/mono_mpeg2_picture_frame.h b/src/mono_mpeg2_picture_frame.h
new file mode 100644
index 00000000..13853a4e
--- /dev/null
+++ b/src/mono_mpeg2_picture_frame.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_MONO_MPEG2_PICTURE_FRAME_H
+#define LIBDCP_MONO_MPEG2_PICTURE_FRAME_H
+
+
+#include "asset_reader.h"
+#include "data.h"
+
+
+namespace dcp {
+
+
+class MonoMPEG2PictureFrame : public Data
+{
+public:
+ MonoMPEG2PictureFrame(MonoMPEG2PictureFrame const&) = delete;
+ MonoMPEG2PictureFrame& operator=(MonoMPEG2PictureFrame const&) = delete;
+
+ /** @return Pointer to MPEG2 data */
+ uint8_t const * data() const override;
+
+ /** @return Pointer to MPEG2 data */
+ uint8_t* data () override;
+
+ /** @return Size of MPEG2 data in bytes */
+ int size() const override;
+
+private:
+ /* XXX: this is a bit of a shame, but I tried friend MonoMPEG2PictureAssetReader and it's
+ rejected by some (seemingly older) GCCs.
+ */
+ friend class AssetReader<ASDCP::MPEG2::MXFReader, MonoMPEG2PictureFrame>;
+
+ MonoMPEG2PictureFrame(ASDCP::MPEG2::MXFReader* reader, int n, std::shared_ptr<DecryptionContext>, bool check_hmac);
+
+ std::shared_ptr<ASDCP::MPEG2::FrameBuffer> _buffer;
+};
+
+
+}
+
+
+#endif
diff --git a/src/mpeg2_picture_asset.cc b/src/mpeg2_picture_asset.cc
new file mode 100644
index 00000000..6cd0b428
--- /dev/null
+++ b/src/mpeg2_picture_asset.cc
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "mpeg2_picture_asset.h"
+
+
+using std::string;
+using namespace dcp;
+
+
+MPEG2PictureAsset::MPEG2PictureAsset(boost::filesystem::path file)
+ : PictureAsset(file)
+{
+
+}
+
+
+void
+MPEG2PictureAsset::read_video_descriptor(ASDCP::MPEG2::VideoDescriptor const& descriptor)
+{
+ _size.width = descriptor.StoredWidth;
+ _size.height = descriptor.StoredHeight;
+ _edit_rate = Fraction(descriptor.EditRate.Numerator, descriptor.EditRate.Denominator);
+ _intrinsic_duration = descriptor.ContainerDuration;
+ _frame_rate = Fraction(descriptor.SampleRate.Numerator, descriptor.SampleRate.Denominator);
+ _screen_aspect_ratio = Fraction(descriptor.AspectRatio.Numerator, descriptor.AspectRatio.Denominator);
+}
+
+
+string
+MPEG2PictureAsset::pkl_type (Standard standard) const
+{
+ DCP_ASSERT(standard == Standard::INTEROP);
+ return "application/x-smpte-mxf;asdcpKind=Picture";
+}
+
+
+string
+MPEG2PictureAsset::static_pkl_type(Standard standard)
+{
+ DCP_ASSERT(standard == Standard::INTEROP);
+ return "application/x-smpte-mxf;asdcpKind=Picture";
+}
diff --git a/src/mpeg2_picture_asset.h b/src/mpeg2_picture_asset.h
new file mode 100644
index 00000000..df882202
--- /dev/null
+++ b/src/mpeg2_picture_asset.h
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_MPEG2_PICTURE_ASSET_H
+#define LIBDCP_MPEG2_PICTURE_ASSET_H
+
+
+/** @file src/mpeg2_picture_asset.h
+ * @brief MPEG2PictureAsset class
+ */
+
+
+#include "picture_asset.h"
+#include <boost/filesystem/path.hpp>
+
+
+namespace ASDCP {
+ namespace MPEG2 {
+ struct VideoDescriptor;
+ }
+}
+
+
+namespace dcp {
+
+
+class MPEG2PictureAsset : public PictureAsset
+{
+public:
+ explicit MPEG2PictureAsset(boost::filesystem::path file);
+
+ static std::string static_pkl_type(Standard standard);
+
+protected:
+ void read_video_descriptor(ASDCP::MPEG2::VideoDescriptor const& descriptor);
+
+private:
+ std::string pkl_type(Standard standard) const override;
+};
+
+
+}
+
+
+#endif
+
diff --git a/src/mpeg2_transcode.cc b/src/mpeg2_transcode.cc
new file mode 100644
index 00000000..ab77f0e1
--- /dev/null
+++ b/src/mpeg2_transcode.cc
@@ -0,0 +1,143 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "compose.hpp"
+#include "exceptions.h"
+#include "mono_mpeg2_picture_frame.h"
+#include "mpeg2_transcode.h"
+extern "C" {
+#include <libavcodec/avcodec.h>
+}
+
+
+using std::shared_ptr;
+using std::vector;
+using namespace dcp;
+
+
+MPEG2Codec::~MPEG2Codec()
+{
+ avcodec_free_context(&_context);
+}
+
+
+
+MPEG2Decompressor::MPEG2Decompressor()
+{
+ _codec = avcodec_find_decoder_by_name("mpeg2video");
+ if (!_codec) {
+ throw MPEG2CodecError("could not find codec");
+ }
+
+ _context = avcodec_alloc_context3(_codec);
+ if (!_context) {
+ throw MPEG2CodecError("could not allocate codec context");
+ }
+
+ int const r = avcodec_open2(_context, _codec, nullptr);
+ if (r < 0) {
+ avcodec_free_context(&_context);
+ throw MPEG2CodecError("could not open codec");
+ }
+
+ _decompressed_frame = av_frame_alloc();
+ if (!_decompressed_frame) {
+ throw std::bad_alloc();
+ }
+}
+
+
+MPEG2Decompressor::~MPEG2Decompressor()
+{
+ av_frame_free(&_decompressed_frame);
+}
+
+
+vector<FFmpegImage>
+MPEG2Decompressor::decompress_frame(shared_ptr<const MonoMPEG2PictureFrame> frame)
+{
+ /* XXX: can we avoid this? */
+ auto copy = av_malloc(frame->size() + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!copy) {
+ throw std::bad_alloc();
+ }
+ memcpy(copy, frame->data(), frame->size());
+
+ AVPacket packet;
+ av_init_packet(&packet);
+ av_packet_from_data(&packet, reinterpret_cast<uint8_t*>(copy), frame->size());
+
+ auto images = decompress_packet(&packet);
+
+ av_packet_unref(&packet);
+
+ return images;
+}
+
+
+vector<FFmpegImage>
+MPEG2Decompressor::flush()
+{
+ return decompress_packet(nullptr);
+}
+
+
+vector<FFmpegImage>
+MPEG2Decompressor::decompress_packet(AVPacket* packet)
+{
+ int const r = avcodec_send_packet(_context, packet);
+ if (r < 0) {
+ throw MPEG2DecompressionError(String::compose("avcodec_send_packet failed (%1)", r));
+ }
+
+ vector<FFmpegImage> images;
+ while (true) {
+ int const r = avcodec_receive_frame(_context, _decompressed_frame);
+ if (r == AVERROR(EAGAIN) || r == AVERROR_EOF) {
+ break;
+ } else if (r < 0) {
+ throw MPEG2DecompressionError("avcodec_receive_frame failed");
+ }
+
+ auto clone = av_frame_clone(_decompressed_frame);
+ if (!clone) {
+ throw std::bad_alloc();
+ }
+
+ images.push_back(FFmpegImage(clone));
+ }
+
+ return images;
+}
+
diff --git a/src/mpeg2_transcode.h b/src/mpeg2_transcode.h
new file mode 100644
index 00000000..ef5c8351
--- /dev/null
+++ b/src/mpeg2_transcode.h
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_MPEG2_TRANSCODE_H
+#define LIBDCP_MPEG2_TRANSCODE_H
+
+
+#include "ffmpeg_image.h"
+#include <memory>
+
+
+struct AVCodec;
+struct AVCodecContext;
+struct AVFrame;
+struct AVPacket;
+
+
+namespace dcp {
+
+
+class MonoMPEG2PictureFrame;
+
+
+class MPEG2Codec
+{
+public:
+ MPEG2Codec() = default;
+ virtual ~MPEG2Codec();
+
+ MPEG2Codec(MPEG2Codec const&) = delete;
+ MPEG2Codec& operator=(MPEG2Codec const&) = delete;
+
+protected:
+ AVCodec const* _codec;
+ AVCodecContext* _context;
+};
+
+
+class MPEG2Decompressor : public MPEG2Codec
+{
+public:
+ MPEG2Decompressor();
+ ~MPEG2Decompressor();
+
+ std::vector<FFmpegImage> decompress_frame(std::shared_ptr<const MonoMPEG2PictureFrame> frame);
+ std::vector<FFmpegImage> flush();
+
+private:
+ std::vector<FFmpegImage> decompress_packet(AVPacket* packet);
+
+ AVFrame* _decompressed_frame;
+};
+
+
+}
+
+
+#endif
diff --git a/src/reel.cc b/src/reel.cc
index fc47239d..acd7c7fc 100644
--- a/src/reel.cc
+++ b/src/reel.cc
@@ -327,7 +327,7 @@ Reel::give_kdm_to_assets (DecryptedKDM const & kdm)
{
for (auto const& i: kdm.keys()) {
if (_main_picture && i.id() == _main_picture->key_id() && _main_picture->asset_ref().resolved()) {
- _main_picture->asset()->set_key (i.key());
+ _main_picture->j2k_asset()->set_key(i.key());
}
if (_main_sound && i.id() == _main_sound->key_id() && _main_sound->asset_ref().resolved()) {
_main_sound->asset()->set_key (i.key());
diff --git a/src/reel_mono_picture_asset.cc b/src/reel_mono_picture_asset.cc
index 04c16d25..81eb4df9 100644
--- a/src/reel_mono_picture_asset.cc
+++ b/src/reel_mono_picture_asset.cc
@@ -47,7 +47,7 @@ using std::shared_ptr;
using namespace dcp;
-ReelMonoPictureAsset::ReelMonoPictureAsset (std::shared_ptr<MonoJ2KPictureAsset> asset, int64_t entry_point)
+ReelMonoPictureAsset::ReelMonoPictureAsset(std::shared_ptr<PictureAsset> asset, int64_t entry_point)
: ReelPictureAsset (asset, entry_point)
{
diff --git a/src/reel_mono_picture_asset.h b/src/reel_mono_picture_asset.h
index 54429ad4..13c6545e 100644
--- a/src/reel_mono_picture_asset.h
+++ b/src/reel_mono_picture_asset.h
@@ -43,6 +43,7 @@
#include "reel_picture_asset.h"
#include "mono_j2k_picture_asset.h"
+#include "mono_mpeg2_picture_asset.h"
namespace dcp {
@@ -57,19 +58,29 @@ class MonoJ2KPictureAsset;
class ReelMonoPictureAsset : public ReelPictureAsset
{
public:
- ReelMonoPictureAsset (std::shared_ptr<MonoJ2KPictureAsset> asset, int64_t entry_point);
+ ReelMonoPictureAsset(std::shared_ptr<PictureAsset> asset, int64_t entry_point);
explicit ReelMonoPictureAsset (std::shared_ptr<const cxml::Node>);
- /** @return the MonoJ2KPictureAsset that this object refers to */
- std::shared_ptr<const MonoJ2KPictureAsset> mono_asset () const {
+ /** @return the MonoJ2KPictureAsset that this object refers to, if applicable */
+ std::shared_ptr<const MonoJ2KPictureAsset> mono_j2k_asset() const {
return asset_of_type<const MonoJ2KPictureAsset>();
}
/** @return the MonoJ2KPictureAsset that this object refers to */
- std::shared_ptr<MonoJ2KPictureAsset> mono_asset () {
+ std::shared_ptr<MonoJ2KPictureAsset> mono_j2k_asset() {
return asset_of_type<MonoJ2KPictureAsset>();
}
+ /** @return the MonoMPEG2PictureAsset that this object refers to, if applicable */
+ std::shared_ptr<const MonoMPEG2PictureAsset> mono_mpeg2_asset() const {
+ return asset_of_type<const MonoMPEG2PictureAsset>();
+ }
+
+ /** @return the MonoMPEG2PictureAsset that this object refers to */
+ std::shared_ptr<MonoMPEG2PictureAsset> mono_mpeg2_asset() {
+ return asset_of_type<MonoMPEG2PictureAsset>();
+ }
+
private:
std::string cpl_node_name (Standard standard) const override;
};
diff --git a/src/reel_picture_asset.cc b/src/reel_picture_asset.cc
index ca22b6fc..37a6bfcc 100644
--- a/src/reel_picture_asset.cc
+++ b/src/reel_picture_asset.cc
@@ -59,7 +59,7 @@ using boost::optional;
using namespace dcp;
-ReelPictureAsset::ReelPictureAsset (shared_ptr<J2KPictureAsset> asset, int64_t entry_point)
+ReelPictureAsset::ReelPictureAsset(shared_ptr<PictureAsset> asset, int64_t entry_point)
: ReelFileAsset (asset, asset->key_id(), asset->id(), asset->edit_rate(), asset->intrinsic_duration(), entry_point)
, _frame_rate (asset->frame_rate ())
, _screen_aspect_ratio (asset->screen_aspect_ratio ())
diff --git a/src/reel_picture_asset.h b/src/reel_picture_asset.h
index 6185f3dd..9f42a5b6 100644
--- a/src/reel_picture_asset.h
+++ b/src/reel_picture_asset.h
@@ -43,6 +43,7 @@
#include "reel_file_asset.h"
#include "j2k_picture_asset.h"
+#include "mpeg2_picture_asset.h"
namespace dcp {
@@ -54,20 +55,41 @@ namespace dcp {
class ReelPictureAsset : public ReelFileAsset
{
public:
- ReelPictureAsset (std::shared_ptr<J2KPictureAsset> asset, int64_t entry_point);
+ ReelPictureAsset(std::shared_ptr<PictureAsset> asset, int64_t entry_point);
explicit ReelPictureAsset (std::shared_ptr<const cxml::Node>);
- /** @return the J2KPictureAsset that this object refers to */
- std::shared_ptr<const J2KPictureAsset> asset () const {
+ /** @return the PictureAsset that this object refers to, if applicable */
+ std::shared_ptr<const PictureAsset> asset() const {
+ return asset_of_type<const PictureAsset>();
+ }
+
+ /** @return the PictureAsset that this object refers to, if applicable */
+ std::shared_ptr<PictureAsset> asset() {
+ return asset_of_type<PictureAsset>();
+ }
+
+ /** @return the J2KPictureAsset that this object refers to, if applicable */
+ std::shared_ptr<const J2KPictureAsset> j2k_asset() const {
return asset_of_type<const J2KPictureAsset>();
}
- /** @return the J2KPictureAsset that this object refers to */
- std::shared_ptr<J2KPictureAsset> asset () {
+ /** @return the J2KPictureAsset that this object refers to, if applicable */
+ std::shared_ptr<J2KPictureAsset> j2k_asset() {
return asset_of_type<J2KPictureAsset>();
}
+ /** @return the MPEG2PictureAsset that this object refers to, if applicable */
+ std::shared_ptr<const MPEG2PictureAsset> mpeg2_asset() const {
+ return asset_of_type<const MPEG2PictureAsset>();
+ }
+
+ /** @return the MPEG2PictureAsset that this object refers to, if applicable */
+ std::shared_ptr<MPEG2PictureAsset> mpeg2_asset() {
+ return asset_of_type<MPEG2PictureAsset>();
+ }
+
virtual xmlpp::Element* write_to_cpl(xmlpp::Element* node, Standard standard) const override;
+
bool equals(std::shared_ptr<const ReelPictureAsset>, EqualityOptions const&, NoteHandler) const;
/** @return picture frame rate */
diff --git a/src/wscript b/src/wscript
index 2ce8e556..47b716cf 100644
--- a/src/wscript
+++ b/src/wscript
@@ -77,6 +77,10 @@ def build(bld):
mono_j2k_picture_asset.cc
mono_j2k_picture_asset_writer.cc
mono_j2k_picture_frame.cc
+ mono_mpeg2_picture_asset.cc
+ mono_mpeg2_picture_frame.cc
+ mpeg2_picture_asset.cc
+ mpeg2_transcode.cc
mxf.cc
name_format.cc
object.cc
@@ -171,6 +175,7 @@ def build(bld):
identity_transfer_function.h
interop_load_font_node.h
interop_subtitle_asset.h
+ ffmpeg_image.h
j2k_picture_asset.h
j2k_picture_asset_writer.h
j2k_transcode.h
@@ -185,6 +190,11 @@ def build(bld):
mono_j2k_picture_asset_reader.h
mono_j2k_picture_asset_writer.h
mono_j2k_picture_frame.h
+ mono_mpeg2_picture_asset.h
+ mono_mpeg2_picture_asset_reader.h
+ mono_mpeg2_picture_frame.h
+ mpeg2_picture_asset.h
+ mpeg2_transcode.h
mxf.h
name_format.h
object.h
@@ -250,7 +260,7 @@ def build(bld):
obj.name = 'libdcp%s' % bld.env.API_VERSION
obj.target = 'dcp%s' % bld.env.API_VERSION
obj.export_includes = ['.']
- obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_DCPOMATIC XERCES'
+ obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_DCPOMATIC XERCES AVCODEC AVUTIL'
obj.source = source
# Library for gcov
@@ -262,7 +272,7 @@ def build(bld):
obj.name = 'libdcp%s_gcov' % bld.env.API_VERSION
obj.target = 'dcp%s_gcov' % bld.env.API_VERSION
obj.export_includes = ['.']
- obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_DCPOMATIC XERCES'
+ obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_DCPOMATIC XERCES AVCODEC AVUTIL'
obj.use = 'libkumu-libdcp%s libasdcp-libdcp%s' % (bld.env.API_VERSION, bld.env.API_VERSION)
obj.source = source
obj.cppflags = ['-fprofile-arcs', '-ftest-coverage', '-fno-inline', '-fno-default-inline', '-fno-elide-constructors', '-g', '-O0']