Bv2.1 6.2.1: Check that the sound MXF Language tag conforms to RFC 5646.
[libdcp.git] / src / verify.cc
index 0d1907fe2b76cee672a993b31652e64e8845ae6f..eec63d511b01536032b071bad4eb9f4c0d72ff16 100644 (file)
@@ -46,6 +46,7 @@
 #include "exceptions.h"
 #include "compose.hpp"
 #include "raw_convert.h"
+#include "smpte_subtitle_asset.h"
 #include <xercesc/util/PlatformUtils.hpp>
 #include <xercesc/parsers/XercesDOMParser.hpp>
 #include <xercesc/parsers/AbstractDOMParser.hpp>
@@ -78,10 +79,10 @@ using std::string;
 using std::cout;
 using std::map;
 using std::max;
-using boost::shared_ptr;
+using std::shared_ptr;
 using boost::optional;
 using boost::function;
-using boost::dynamic_pointer_cast;
+using std::dynamic_pointer_cast;
 
 using namespace dcp;
 using namespace xercesc;
@@ -394,6 +395,17 @@ verify_asset (shared_ptr<const DCP> dcp, shared_ptr<const ReelMXF> reel_mxf, fun
 }
 
 
+void
+verify_language_tag (string tag, list<VerificationNote>& notes)
+{
+       try {
+               dcp::LanguageTag test (tag);
+       } catch (dcp::LanguageTagError &) {
+               notes.push_back (VerificationNote(VerificationNote::VERIFY_BV21_ERROR, VerificationNote::BAD_LANGUAGE, tag));
+       }
+}
+
+
 enum VerifyPictureAssetResult
 {
        VERIFY_PICTURE_ASSET_RESULT_GOOD,
@@ -411,7 +423,7 @@ biggest_frame_size (shared_ptr<const MonoPictureFrame> frame)
 int
 biggest_frame_size (shared_ptr<const StereoPictureFrame> frame)
 {
-       return max(frame->left_j2k_size(), frame->right_j2k_size());
+       return max(frame->left()->size(), frame->right()->size());
 }
 
 
@@ -520,26 +532,41 @@ verify_main_sound_asset (
        list<VerificationNote>& notes
        )
 {
-       stage ("Checking sound asset hash", reel->main_sound()->asset()->file());
+       shared_ptr<dcp::SoundAsset> asset = reel->main_sound()->asset();
+       stage ("Checking sound asset hash", asset->file());
        VerifyAssetResult const r = verify_asset (dcp, reel->main_sound(), progress);
        switch (r) {
                case VERIFY_ASSET_RESULT_BAD:
                        notes.push_back (
                                VerificationNote(
-                                       VerificationNote::VERIFY_ERROR, VerificationNote::SOUND_HASH_INCORRECT, *reel->main_sound()->asset()->file()
+                                       VerificationNote::VERIFY_ERROR, VerificationNote::SOUND_HASH_INCORRECT, *asset->file()
                                        )
                                );
                        break;
                case VERIFY_ASSET_RESULT_CPL_PKL_DIFFER:
                        notes.push_back (
                                VerificationNote(
-                                       VerificationNote::VERIFY_ERROR, VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE, *reel->main_sound()->asset()->file()
+                                       VerificationNote::VERIFY_ERROR, VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE, *asset->file()
                                        )
                                );
                        break;
                default:
                        break;
        }
+
+       stage ("Checking sound asset metadata", asset->file());
+
+       verify_language_tag (asset->language(), notes);
+}
+
+
+static void
+verify_main_subtitle_reel (shared_ptr<const ReelSubtitleAsset> reel_asset, list<VerificationNote>& notes)
+{
+       /* XXX: is Language compulsory? */
+       if (reel_asset->language()) {
+               verify_language_tag (*reel_asset->language(), notes);
+       }
 }
 
 
@@ -551,12 +578,19 @@ verify_main_subtitle_asset (
        list<VerificationNote>& notes
        )
 {
-       shared_ptr<ReelSubtitleAsset> reel_asset = reel->main_subtitle ();
-       stage ("Checking subtitle XML", reel->main_subtitle()->asset()->file());
+       shared_ptr<SubtitleAsset> asset = reel->main_subtitle()->asset();
+       stage ("Checking subtitle XML", asset->file());
        /* Note: we must not use SubtitleAsset::xml_as_string() here as that will mean the data on disk
         * gets passed through libdcp which may clean up and therefore hide errors.
         */
-       validate_xml (reel->main_subtitle()->asset()->raw_xml(), xsd_dtd_directory, notes);
+       validate_xml (asset->raw_xml(), xsd_dtd_directory, notes);
+
+       shared_ptr<SMPTESubtitleAsset> smpte = dynamic_pointer_cast<SMPTESubtitleAsset>(asset);
+       if (smpte) {
+               if (smpte->language()) {
+                       verify_language_tag (*smpte->language(), notes);
+               }
+       }
 }
 
 
@@ -591,6 +625,10 @@ dcp::verify (
                        notes.push_back (VerificationNote(VerificationNote::VERIFY_ERROR, VerificationNote::GENERAL_READ, string(e.what())));
                }
 
+               if (dcp->standard() != dcp::SMPTE) {
+                       notes.push_back (VerificationNote(VerificationNote::VERIFY_BV21_ERROR, VerificationNote::NOT_SMPTE));
+               }
+
                BOOST_FOREACH (shared_ptr<CPL> cpl, dcp->cpls()) {
                        stage ("Checking CPL", cpl->file());
                        validate_xml (cpl->file().get(), xsd_dtd_directory, notes);
@@ -638,8 +676,11 @@ dcp::verify (
                                        verify_main_sound_asset (dcp, reel, stage, progress, notes);
                                }
 
-                               if (reel->main_subtitle() && reel->main_subtitle()->asset_ref().resolved()) {
-                                       verify_main_subtitle_asset (reel, stage, xsd_dtd_directory, notes);
+                               if (reel->main_subtitle()) {
+                                       verify_main_subtitle_reel (reel->main_subtitle(), notes);
+                                       if (reel->main_subtitle()->asset_ref().resolved()) {
+                                               verify_main_subtitle_asset (reel, stage, xsd_dtd_directory, notes);
+                                       }
                                }
                        }
                }
@@ -698,6 +739,10 @@ dcp::note_to_string (dcp::VerificationNote note)
                return String::compose("The instantaneous bit rate of the picture asset %1 is close to the limit of 250Mbit/s in at least one place.", note.file()->filename());
        case dcp::VerificationNote::EXTERNAL_ASSET:
                return String::compose("An asset that this DCP refers to is not included in the DCP.  It may be a VF.  Missing asset is %1.", note.note().get());
+       case dcp::VerificationNote::NOT_SMPTE:
+               return "This DCP does not use the SMPTE standard, which is required for Bv2.1 compliance.";
+       case dcp::VerificationNote::BAD_LANGUAGE:
+               return String::compose("The DCP specifies a language '%1' which does not conform to the RFC 5646 standard.", note.note().get());
        }
 
        return "";