channel assignment
authorjhurst <jhurst@cinecert.com>
Fri, 13 Feb 2009 05:00:31 +0000 (05:00 +0000)
committerjhurst <>
Fri, 13 Feb 2009 05:00:31 +0000 (05:00 +0000)
12 files changed:
src/AS_DCP.h
src/AS_DCP_PCM.cpp
src/KM_error.h
src/KM_tai.cpp
src/KM_util.cpp
src/MDD.cpp
src/MDD.h
src/Metadata.cpp
src/Metadata.h
src/PCM_Parser.cpp
src/Wav.cpp
src/asdcp-test.cpp

index e1cc2614f8e09a946980c1ae1500884090074bef..70367ce7eb0e7cd75275a87c2ad3b97a0eea5ec8 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2003-2008, John Hurst
+Copyright (c) 2003-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -749,9 +749,22 @@ namespace ASDCP {
        };
     } // namespace MPEG2
 
+  //---------------------------------------------------------------------------------
   //
   namespace PCM
     {
+      // The channel format will normally be CF_NONE. Unless you have read and understand
+      // SMPTE 429-2-2009 Annex A you should leave it as-is. If you want to label your channel
+      // format and it is one of the fomats given in 429-2, select the appropriate value
+      // from this enum and use it in the ChannelFormat element of the AudioDescriptor struct.
+      //
+      enum ChannelFormat_t {
+       CF_NONE,
+       CF_CFG_1, // 5.1 with optional HI/VI
+       CF_CFG_2, // 6.1 (5.1 + center surround) with optional HI/VI
+       CF_CFG_3, // 7.1 with optional HI/VI
+      };
+
       struct AudioDescriptor
        {
          Rational SampleRate;         // rate of frame wrapping
@@ -763,6 +776,7 @@ namespace ASDCP {
          ui32_t   AvgBps;             // 
          ui32_t   LinkedTrackID;      // 
          ui32_t   ContainerDuration;  // number of frames
+         ChannelFormat_t ChannelFormat; // audio channel arrangement
       };
 
       // Print AudioDescriptor to std::ostream
@@ -901,6 +915,7 @@ namespace ASDCP {
        };
     } // namespace PCM
 
+  //---------------------------------------------------------------------------------
   //
   namespace JP2K
     {
@@ -1229,6 +1244,7 @@ namespace ASDCP {
        };
     } // namespace JP2K
 
+  //---------------------------------------------------------------------------------
   //
   namespace TimedText
     {
index a50f24b6967c87a28ab43e53591e2851b0faae77..6cf907e1c01be403d08c4ce005efce932e3329f1 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2008, John Hurst
+Copyright (c) 2004-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -39,6 +39,15 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 static std::string PCM_PACKAGE_LABEL = "File Package: SMPTE 382M frame wrapping of wave audio";
 static std::string SOUND_DEF_LABEL = "Sound Track";
 
+static byte_t SNDFMT_CFG_1_UL[16] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b,
+                                     0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x01, 0x00 };
+
+static byte_t SNDFMT_CFG_2_UL[16] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b,
+                                     0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x02, 0x00 };
+
+static byte_t SNDFMT_CFG_3_UL[16] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b,
+                                     0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x03, 0x00 };
+
 //
 Result_t
 PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, MXF::WaveAudioDescriptor* ADescObj)
@@ -53,6 +62,24 @@ PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, MXF::WaveAudioDescriptor* ADescObj)
   ADescObj->AvgBps = ADesc.AvgBps;
   ADescObj->LinkedTrackID = ADesc.LinkedTrackID;
   ADescObj->ContainerDuration = ADesc.ContainerDuration;
+
+  ADescObj->ChannelAssignment.Reset();
+
+  switch ( ADesc.ChannelFormat )
+    {
+      case PCM::CF_CFG_1:
+       ADescObj->ChannelAssignment = UL(SNDFMT_CFG_1_UL);
+       break;
+
+      case PCM::CF_CFG_2:
+       ADescObj->ChannelAssignment = UL(SNDFMT_CFG_2_UL);
+       break;
+
+      case PCM::CF_CFG_3:
+       ADescObj->ChannelAssignment = UL(SNDFMT_CFG_3_UL);
+       break;
+    }
+
   return RESULT_OK;
 }
 
@@ -71,6 +98,21 @@ MD_to_PCM_ADesc(MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc)
   ADesc.LinkedTrackID = ADescObj->LinkedTrackID;
   assert(ADescObj->ContainerDuration <= 0xFFFFFFFFL);
   ADesc.ContainerDuration = (ui32_t) ADescObj->ContainerDuration;
+
+  ADesc.ChannelFormat = PCM::CF_NONE;
+
+  if ( ADescObj->ChannelAssignment.HasValue() )
+    {
+      if ( ADescObj->ChannelAssignment == UL(SNDFMT_CFG_1_UL) )
+       ADesc.ChannelFormat = PCM::CF_CFG_1;
+
+      else if ( ADescObj->ChannelAssignment == UL(SNDFMT_CFG_2_UL) )
+       ADesc.ChannelFormat = PCM::CF_CFG_2;
+
+      else if ( ADescObj->ChannelAssignment == UL(SNDFMT_CFG_3_UL) )
+       ADesc.ChannelFormat = PCM::CF_CFG_3;
+    }
+
   return RESULT_OK;
 }
 
index f8b7bdeb13c9b99011480ada41f046ff9672e72e..c17fe76ecf57e1c9a5b16ad8e209b5d8c0c4c962 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2008, John Hurst
+Copyright (c) 2004-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -87,6 +87,7 @@ namespace Kumu
   const Result_t RESULT_ENDOFFILE  (-17,  "Attempt to read past end of file.");
   const Result_t RESULT_FILEEXISTS (-18,  "Filename already exists.");
   const Result_t RESULT_NOTAFILE   (-19,  "Filename not found.");
+  const Result_t RESULT_UNKNOWN    (-20,  "Unknown result code.");
 } // namespace Kumu
 
 //--------------------------------------------------------------------------------
index dca8471449e13d33d7acdbae95519eb7cc2610d7..f6cbea5109a5231a09cda21a988dd414854d3baf 100644 (file)
@@ -193,6 +193,7 @@ const Kumu::TAI::tai&
 Kumu::TAI::tai::operator=(const Kumu::TAI::caltime& rhs)
 {
   caltime_tai(&rhs, this);
+  return *this;
 }
 
 //
@@ -200,6 +201,7 @@ const Kumu::TAI::caltime&
 Kumu::TAI::caltime::operator=(const Kumu::TAI::tai& rhs)
 {
   caltime_utc(this, &rhs);
+  return *this;
 }
 
 
index 46dbfa6c07a26abdc7557a7bcdd7b608f0089595..43b00a4211ccd0cfe3c9f81425719eb8a087ade8 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2006, John Hurst
+Copyright (c) 2005-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -40,6 +40,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <map>
 #include <string>
 
+#define CONFIG_RANDOM_UUID
+
 const char*
 Kumu::Version()
 {
@@ -75,8 +77,7 @@ Kumu::Result_t::Find(int v)
        return *s_ResultMap[i].result;
     }
 
-  DefaultLogSink().Error("Unknown result code: %ld\n", v);
-  return RESULT_FAIL;
+  return RESULT_UNKNOWN;
 }
 
 //
@@ -373,6 +374,38 @@ Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
   return 0;
 }
 
+#ifdef CONFIG_RANDOM_UUID
+
+// convert a memory region to a NULL-terminated hexadecimal string
+//
+static const char*
+bin2hex_rand(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
+{
+  if ( bin_buf == 0
+       || str_buf == 0
+       || ((bin_len * 2) + 1) > str_len )
+    return 0;
+
+  char* p = str_buf;
+  Kumu::mem_ptr<byte_t> rand_buf = new byte_t[bin_len];
+  Kumu::FortunaRNG RNG;
+  RNG.FillRandom(rand_buf, bin_len);
+
+  for ( ui32_t i = 0; i < bin_len; i++ )
+    {
+      *p = (bin_buf[i] >> 4) & 0x0f;
+      *p += *p < 10 ? 0x30 : (( ((rand_buf[i] & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
+      p++;
+
+      *p = bin_buf[i] & 0x0f;
+      *p += *p < 10 ? 0x30 : (( (((rand_buf[i] >> 1) & 0x01) == 0) ? 0x61 : 0x41 ) - 10);
+      p++;
+    }
+
+  *p = '\0';
+  return str_buf;
+}
+#endif
 
 // convert a memory region to a NULL-terminated hexadecimal string
 //
@@ -384,6 +417,12 @@ Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_l
        || ((bin_len * 2) + 1) > str_len )
     return 0;
 
+#ifdef CONFIG_RANDOM_UUID
+  const char* use_random_uuid  = getenv("KM_USE_RANDOM_UUID");
+  if ( use_random_uuid != 0 && use_random_uuid[0] != 0 && use_random_uuid[0] != '0' )
+    return bin2hex_rand(bin_buf, bin_len, str_buf, str_len);
+#endif
+
   char* p = str_buf;
 
   for ( ui32_t i = 0; i < bin_len; i++ )
index 73f22c790ff8253a39761f39b63c80fce13a6721..da0163fb797e4c1268ce6533f50a314d0b71c17f 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2006, John Hurst
+Copyright (c) 2006-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -845,6 +845,9 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
   { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x0c, // 269
       0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x63, 0x00 },
     {0}, false, "StereoscopicPictureSubDescriptor" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x07, // 270
+      0x04, 0x02, 0x01, 0x01, 0x05, 0x00, 0x00, 0x00 },
+    {0x3d, 0x32}, true, "WaveAudioDescriptor_ChannelAssignment" },
 
   { {0}, {0}, false, 0 }
 };
index e3145f5be50d5716135a1f7a24b6230195a03c87..5ec2b2336902d2dd5873072abcb694bda3d3ff6e 100755 (executable)
--- a/src/MDD.h
+++ b/src/MDD.h
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2006, John Hurst
+Copyright (c) 2006-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -305,6 +305,7 @@ namespace ASDCP {
        MDD_DMSegment_Duration, // 267
        MDD_DMSegment_TrackIDList, // 268
        MDD_StereoscopicPictureSubDescriptor, // 269
+        MDD_WaveAudioDescriptor_ChannelAssignment,  // 270
        MDD_Max,
     }; // enum MDD_t
 } // namespaceASDCP
index 838fc53c5008be5d6b935904b09e2476a773fa66..f509aaa455d430eb750068f19bb9a1f6ca016c5f 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2007, John Hurst
+Copyright (c) 2005-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -977,6 +977,7 @@ WaveAudioDescriptor::InitFromTLVSet(TLVReader& TLVSet)
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(WaveAudioDescriptor, BlockAlign));
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(WaveAudioDescriptor, SequenceOffset));
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(WaveAudioDescriptor, AvgBps));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(WaveAudioDescriptor, ChannelAssignment));
   return result;
 }
 
@@ -988,6 +989,7 @@ WaveAudioDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(WaveAudioDescriptor, BlockAlign));
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(WaveAudioDescriptor, SequenceOffset));
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(WaveAudioDescriptor, AvgBps));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(WaveAudioDescriptor, ChannelAssignment));
   return result;
 }
 
@@ -1005,6 +1007,7 @@ WaveAudioDescriptor::Dump(FILE* stream)
   fprintf(stream, "  %22s = %d\n",  "BlockAlign", BlockAlign);
   fprintf(stream, "  %22s = %d\n",  "SequenceOffset", SequenceOffset);
   fprintf(stream, "  %22s = %d\n",  "AvgBps", AvgBps);
+  fprintf(stream, "  %22s = %s\n",  "ChannelAssignment", ChannelAssignment.EncodeString(identbuf, IdentBufferLen));
 }
 
 //
index 207e031daf23130e83c05c32573b49a90a187c46..5117425552ba055004f0c9c130ae89769792073a 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2007, John Hurst
+Copyright (c) 2005-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -363,6 +363,7 @@ namespace ASDCP
           ui16_t BlockAlign;
           ui8_t SequenceOffset;
           ui32_t AvgBps;
+          UL ChannelAssignment;
 
          WaveAudioDescriptor() : BlockAlign(0), SequenceOffset(0), AvgBps(0) {}
          virtual ~WaveAudioDescriptor() {}
index f0caef270fc6c58be48e4af6746a47834b0bd041..2f96d2359047b6a6a9bd6173f47d85f1946b3aae 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2006, John Hurst
+Copyright (c) 2004-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -110,6 +110,7 @@ ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const char* filename, const Ration
          m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
          m_DataLength = WavHeader.data_len;
          m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
+         m_ADesc.ChannelFormat = PCM::CF_NONE;
          Reset();
        }
       else
@@ -125,6 +126,7 @@ ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const char* filename, const Ration
              m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
              m_DataLength = AIFFHeader.data_len;
              m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
+             m_ADesc.ChannelFormat = PCM::CF_NONE;
              Reset();
            }
        }
index ff063fbf09073c1dc3cc73b1bc34c78cfe3afa90..886a1839b28edabfd4c706dd951a2bd657a683d8 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2006, John Hurst
+Copyright (c) 2005-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -65,6 +65,7 @@ ASDCP::Wav::SimpleWaveHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDC
   ADesc.QuantizationBits = bitspersample;
   ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
   ADesc.ContainerDuration = data_len / FrameBufferSize;
+  ADesc.ChannelFormat = PCM::CF_NONE;
 }
 
 
@@ -268,6 +269,7 @@ ASDCP::AIFF::SimpleAIFFHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASD
   ADesc.AvgBps = (ui32_t) (ADesc.BlockAlign * ADesc.AudioSamplingRate.Quotient());
   ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
   ADesc.ContainerDuration = data_len / FrameBufferSize;
+  ADesc.ChannelFormat = PCM::CF_NONE;
 }
 
 //
index 7889974b59b1fd63c878b75c7ecfe4b3109933f4..d957407fc0bd2fc1150dc78aa221e8cbcaa060dd 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2003-2008, John Hurst
+Copyright (c) 2003-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -116,8 +116,8 @@ usage(FILE* stream = stdout)
 {
   fprintf(stream, "\
 USAGE: %s -c <output-file> [-3] [-b <buffer-size>] [-d <duration>] [-e|-E]\n\
-       [-f <start-frame>] [-j <key-id-string>] [-k <key-string>] [-L] [-M]\n\
-       [-p <frame-rate>] [-R] [-s <num>] [-v] [-W]\n\
+       [-f <start-frame>] [-j <key-id-string>] [-k <key-string>] [-l <label>]\n\
+       [-L] [-M] [-p <frame-rate>] [-R] [-s <num>] [-v] [-W]\n\
        <input-file> [<input-file-2> ...]\n\
 \n\
        %s [-h|-help] [-V]\n\
@@ -170,6 +170,9 @@ Read/Write Options:\n\
                       Defaults to 4,194,304 (4MB)\n\
   -d <duration>     - Number of frames to process, default all\n\
   -f <start-frame>  - Starting frame number, default 0\n\
+  -l <label>        - Use given channel format label when writing MXF sound\n\
+                      files. SMPTE 429-2 labels: '5.1', '6.1', '7.1'. Default\n\
+                      is no label (valid for Interop only).\n\
   -L                - Write SMPTE UL values instead of MXF Interop\n\
   -p <rate>         - fps of picture when wrapping PCM or JP2K:\n\
                       Use one of [23|24|48], 24 is default\n\
@@ -215,6 +218,23 @@ enum MajorMode_t
   MMT_UL_LIST,
 };
 
+//
+PCM::ChannelFormat_t
+decode_channel_fmt(const std::string& label_name)
+{
+  if ( label_name == "5.1" )
+    return PCM::CF_CFG_1;
+
+  else if ( label_name == "6.1" )
+    return PCM::CF_CFG_2;
+  
+  else if ( label_name == "7.1" )
+    return PCM::CF_CFG_3;
+
+  fprintf(stderr, "Error decoding channel format string: %s\n", label_name.c_str());
+  fprintf(stderr, "Expecting '5.1', '6.1', or '7.1'\n");
+  return PCM::CF_NONE;
+}
 
 //
 //
@@ -254,6 +274,7 @@ public:
   byte_t key_value[KeyLen];  // value of given encryption key (when key_flag is true)
   byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
   const char* filenames[MAX_IN_FILES]; // list of filenames to be processed
+  PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
 
   //
   Rational PictureRate()
@@ -279,7 +300,8 @@ public:
     no_write_flag(false), version_flag(false), help_flag(false), stereo_image_flag(false),
     number_width(6), start_frame(0),
     duration(0xffffffff), duration_flag(false), do_repeat(false), use_smpte_labels(false),
-    picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_count(0), file_root(0), out_file(0)
+    picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_count(0), file_root(0), out_file(0),
+    channel_fmt(PCM::CF_NONE)
   {
     memset(key_value, 0, KeyLen);
     memset(key_id_value, 0, UUIDlen);
@@ -366,6 +388,10 @@ public:
                }
                break;
 
+             case 'l':
+               TEST_EXTRA_ARG(i, 'l');
+               channel_fmt = decode_channel_fmt(argv[i]);
+               break;
 
              case 'L': use_smpte_labels = true; break;
              case 'M': write_hmac = false; break;
@@ -1158,6 +1184,12 @@ write_PCM_file(CommandOptions& Options)
 
       ADesc.SampleRate = PictureRate;
       FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+      ADesc.ChannelFormat = Options.channel_fmt;
+
+      if ( Options.use_smpte_labels && ADesc.ChannelFormat == PCM::CF_NONE)
+       {
+         fprintf(stderr, "ATTENTION! Writing SMPTE audio without ChannelAssignment property (see option -l)\n");
+       }
 
       if ( Options.verbose_flag )
        {