o Replaced WIN32 directory scanner with dirent_win.h
[asdcplib.git] / src / as-02-unwrap.cpp
index b8f69a0a169bf0946f7a8ca20659a62153cef869..1104be06ad8fbf879d7a57d8b937c840cf3d4fde 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2011-2014, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
 John Hurst
 
 All rights reserved.
@@ -69,7 +69,7 @@ banner(FILE* stream = stdout)
 {
   fprintf(stream, "\n\
 %s (asdcplib %s)\n\n\
-Copyright (c) 2011-2014, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\
+Copyright (c) 2011-2015, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\
 asdcplib may be copied only under the terms of the license found at\n\
 the top of every file in the asdcplib distribution kit.\n\n\
 Specify the -h (help) option for further information about %s\n\n",
@@ -86,7 +86,7 @@ USAGE: %s [-h|-help] [-V]\n\
        %s [-1|-2] [-b <buffer-size>] [-d <duration>]\n\
        [-f <starting-frame>] [-m] [-p <frame-rate>] [-R] [-s <size>] [-v] [-W]\n\
        [-w] <input-file> [<file-prefix>]\n\n",
-         PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME);
+         PROGRAM_NAME, PROGRAM_NAME);
 
   fprintf(stream, "\
 Options:\n\
@@ -144,6 +144,7 @@ public:
   byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
   PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
   const char* input_filename;
+  const char* extension;
   std::string prefix_buffer;
 
   //
@@ -178,7 +179,7 @@ public:
 
              case 'b':
                TEST_EXTRA_ARG(i, 'b');
-               fb_size = abs(atoi(argv[i]));
+               fb_size = Kumu::xabs(strtol(argv[i], 0, 10));
 
                if ( verbose_flag )
                  fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
@@ -188,12 +189,17 @@ public:
              case 'd':
                TEST_EXTRA_ARG(i, 'd');
                duration_flag = true;
-               duration = abs(atoi(argv[i]));
+               duration = Kumu::xabs(strtol(argv[i], 0, 10));
+               break;
+
+             case 'e':
+               TEST_EXTRA_ARG(i, 'e');
+               extension = argv[i];
                break;
 
              case 'f':
                TEST_EXTRA_ARG(i, 'f');
-               start_frame = abs(atoi(argv[i]));
+               start_frame = Kumu::xabs(strtol(argv[i], 0, 10));
                break;
 
              case 'h': help_flag = true; break;
@@ -201,12 +207,12 @@ public:
 
              case 'p':
                TEST_EXTRA_ARG(i, 'p');
-               picture_rate = abs(atoi(argv[i]));
+               picture_rate = Kumu::xabs(strtol(argv[i], 0, 10));
                break;
 
              case 's':
                TEST_EXTRA_ARG(i, 's');
-               fb_dump_size = abs(atoi(argv[i]));
+               fb_dump_size = Kumu::xabs(strtol(argv[i], 0, 10));
                break;
 
              case 'V': version_flag = true; break;
@@ -215,7 +221,7 @@ public:
 
              case 'w':
                TEST_EXTRA_ARG(i, 'w');
-               number_width = abs(atoi(argv[i]));
+               number_width = Kumu::xabs(strtol(argv[i], 0, 10));
                break;
 
              case 'Z': j2c_pedantic = false; break;
@@ -376,19 +382,34 @@ read_JP2K_file(CommandOptions& Options)
     {
       result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
 
-      if ( ASDCP_SUCCESS(result) )
+      char filename[1024];
+      snprintf(filename, 1024, name_format, Options.file_prefix, i);
+
+      if ( ASDCP_SUCCESS(result) && Options.verbose_flag )
+       {
+         printf("Frame %d, %d bytes", i, FrameBuffer.Size());
+
+         if ( ! Options.no_write_flag )
+           {
+             printf(" -> %s", filename);
+           }
+
+         printf("\n");
+       }
+
+      if ( ASDCP_SUCCESS(result)  && ( ! Options.no_write_flag ) )
        {
          Kumu::FileWriter OutFile;
-         char filename[256];
          ui32_t write_count;
-         snprintf(filename, 256, name_format, Options.file_prefix, i);
          result = OutFile.OpenWrite(filename);
 
          if ( ASDCP_SUCCESS(result) )
            result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
 
-         if ( Options.verbose_flag )
-           FrameBuffer.Dump(stderr, Options.fb_dump_size);
+         if ( ASDCP_SUCCESS(result) && Options.verbose_flag )
+           {
+             FrameBuffer.Dump(stderr, Options.fb_dump_size);
+           }
        }
     }
 
@@ -456,6 +477,20 @@ read_PCM_file(CommandOptions& Options)
              last_frame = wave_descriptor->ContainerDuration;
            }
 
+         if ( last_frame == 0 )
+           {
+             fprintf(stderr, "ContainerDuration not set in index, attempting to use Duration from SourceClip.\n");
+             result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_SourceClip), &tmp_obj);
+             if ( KM_SUCCESS(result))
+               {
+                 ASDCP::MXF::SourceClip *sourceClip = dynamic_cast<ASDCP::MXF::SourceClip*>(tmp_obj);
+                 if ( ! sourceClip->Duration.empty() )
+                   {
+                     last_frame = sourceClip->Duration;
+                   }
+               }
+           }
+
          if ( last_frame == 0 )
            {
              fprintf(stderr, "Unable to determine file duration.\n");
@@ -535,6 +570,13 @@ read_PCM_file(CommandOptions& Options)
              FrameBuffer.Dump(stderr, Options.fb_dump_size);
            }
 
+         if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
+           {
+             fprintf(stderr, "Last frame is incomplete, padding with zeros.\n");
+             // actually, it has already been zeroed for us, we just need to recognize the appropriate size
+             FrameBuffer.Size(FrameBuffer.Capacity());
+           }
+
          result = OutWave.WriteFrame(FrameBuffer);
        }
     }
@@ -543,6 +585,87 @@ read_PCM_file(CommandOptions& Options)
 }
 
 
+//------------------------------------------------------------------------------------------
+// TimedText essence
+
+// Read one or more timed text streams from a plaintext AS-02 file
+//
+Result_t
+read_timed_text_file(CommandOptions& Options)
+{
+  AESDecContext*     Context = 0;
+  HMACContext*       HMAC = 0;
+  AS_02::TimedText::MXFReader     Reader;
+  TimedText::FrameBuffer   FrameBuffer(Options.fb_size);
+  //ASDCP::TimedText::FrameBuffer   FrameBuffer(Options.fb_size);
+  AS_02::TimedText::TimedTextDescriptor TDesc;
+  ASDCP::MXF::TimedTextDescriptor *tt_descriptor = 0;
+
+  Result_t result = Reader.OpenRead(Options.input_filename);
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_TimedTextDescriptor),
+                                                    reinterpret_cast<MXF::InterchangeObject**>(&tt_descriptor));
+    if ( Options.verbose_flag ) {
+       tt_descriptor->Dump();
+    }
+
+
+  if ( ASDCP_FAILURE(result) )
+    return result;
+
+  std::string XMLDoc;
+  std::string out_path = Kumu::PathDirname(Options.file_prefix);
+  ui32_t write_count;
+  char buf[64];
+  TimedText::ResourceList_t::const_iterator ri;
+
+  result = Reader.ReadTimedTextResource(XMLDoc);
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      Reader.FillTimedTextDescriptor(TDesc);
+      FrameBuffer.Capacity(Options.fb_size);
+
+      if ( Options.verbose_flag )
+       TimedText::DescriptorDump(TDesc);
+    }
+
+  if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
+    {
+      Kumu::FileWriter Writer;
+      result = Writer.OpenWrite(Options.file_prefix);
+
+      if ( ASDCP_SUCCESS(result) )
+       result = Writer.Write(reinterpret_cast<const byte_t*>(XMLDoc.c_str()), XMLDoc.size(), &write_count);
+    }
+
+  for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
+    {
+      result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC);
+
+      if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
+       {
+         Kumu::FileWriter Writer;
+         if (out_path != "") {
+                 result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str());
+         } else {
+                 // Workaround for a bug in Kumu::PathJoin
+                 result = Writer.OpenWrite(Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64));
+         }
+
+         if ( ASDCP_SUCCESS(result) )
+           result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count);
+
+             if ( Options.verbose_flag )
+               FrameBuffer.Dump(stderr, Options.fb_dump_size);
+       }
+    }
+    }
+  return result;
+}
+
 //
 int
 main(int argc, const char** argv)
@@ -581,8 +704,12 @@ main(int argc, const char** argv)
          result = read_PCM_file(Options);
          break;
 
+       case ESS_AS02_TIMED_TEXT:
+         result = read_timed_text_file(Options);
+         break;
+
        default:
-         fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.input_filename);
+         fprintf(stderr, "%s: Unknown file type (%d), not AS-02 essence.\n", Options.input_filename, EssenceType);
          return 5;
        }
     }