Add command line support for projection_type

Add command line for projection_type, projection_pose_{yaw,pitch,roll}.
Use a file for projection_private data to allow setting the contents
for cubemap, equirect, or mesh.

Change-Id: I45f20c68a5d01150d0fb3882ad1c587a8b9f63f2
diff --git a/common/file_util.cc b/common/file_util.cc
index 6dab146..252e74b 100644
--- a/common/file_util.cc
+++ b/common/file_util.cc
@@ -65,6 +65,15 @@
   return file_size;
 }
 
+bool GetFileContents(const std::string& file_name, std::string* contents) {
+  std::ifstream file(file_name.c_str());
+  *contents = std::string(static_cast<size_t>(GetFileSize(file_name)), 0);
+  if (file.good() && contents->size()) {
+    file.read(&(*contents)[0], contents->size());
+  }
+  return !file.fail();
+}
+
 TempFileDeleter::TempFileDeleter() { file_name_ = GetTempFileName(); }
 
 TempFileDeleter::~TempFileDeleter() {
diff --git a/common/file_util.h b/common/file_util.h
index 0e71eac..a873734 100644
--- a/common/file_util.h
+++ b/common/file_util.h
@@ -22,6 +22,9 @@
 // Returns size of file specified by |file_name|, or 0 upon failure.
 uint64_t GetFileSize(const std::string& file_name);
 
+// Gets the contents file_name as a string. Returns false on error.
+bool GetFileContents(const std::string& file_name, std::string* contents);
+
 // Manages life of temporary file specified at time of construction. Deletes
 // file upon destruction.
 class TempFileDeleter {
@@ -38,4 +41,4 @@
 
 }  // namespace libwebm
 
-#endif  // LIBWEBM_COMMON_FILE_UTIL_H_
\ No newline at end of file
+#endif  // LIBWEBM_COMMON_FILE_UTIL_H_
diff --git a/mkvmuxer_sample.cc b/mkvmuxer_sample.cc
index b590c89..e534582 100644
--- a/mkvmuxer_sample.cc
+++ b/mkvmuxer_sample.cc
@@ -62,11 +62,21 @@
   printf("  -copy_input_duration        >0 Copies the input duration\n");
   printf("\n");
   printf("Video options:\n");
-  printf("  -display_width <int>        Display width in pixels\n");
-  printf("  -display_height <int>       Display height in pixels\n");
-  printf("  -pixel_width <int>          Override pixel width\n");
-  printf("  -pixel_height <int>         Override pixel height\n");
-  printf("  -stereo_mode <int>          3D video mode\n");
+  printf("  -display_width <int>           Display width in pixels\n");
+  printf("  -display_height <int>          Display height in pixels\n");
+  printf("  -pixel_width <int>             Override pixel width\n");
+  printf("  -pixel_height <int>            Override pixel height\n");
+  printf("  -projection_type <int>         Set/override projection type:\n");
+  printf("                                   0: Rectangular\n");
+  printf("                                   1: Equirectangular\n");
+  printf("                                   2: Cube map\n");
+  printf("                                   3: Mesh\n");
+  printf("  -projection_file <string>      Override projection private data");
+  printf("                                 with contents of this file\n");
+  printf("  -projection_pose_yaw <float>   Projection pose yaw\n");
+  printf("  -projection_pose_pitch <float> Projection pose pitch\n");
+  printf("  -projection_pose_roll <float>  Projection pose roll\n");
+  printf("  -stereo_mode <int>             3D video mode\n");
   printf("\n");
   printf("VP9 options:\n");
   printf("  -profile <int>              VP9 profile\n");
@@ -154,6 +164,32 @@
   return 0;  // not a WebVTT arg
 }
 
+bool CopyVideoProjection(const mkvparser::Projection& parser_projection,
+                         mkvmuxer::Projection* muxer_projection) {
+  typedef mkvmuxer::Projection::ProjectionType MuxerProjType;
+  const int kTypeNotPresent = mkvparser::Projection::kTypeNotPresent;
+  if (parser_projection.type != kTypeNotPresent) {
+    muxer_projection->set_type(
+        static_cast<MuxerProjType>(parser_projection.type));
+  }
+  if (parser_projection.private_data &&
+      parser_projection.private_data_length > 0) {
+    if (!muxer_projection->SetProjectionPrivate(
+            parser_projection.private_data,
+            parser_projection.private_data_length)) {
+      return false;
+    }
+  }
+
+  const float kValueNotPresent = mkvparser::Projection::kValueNotPresent;
+  if (parser_projection.pose_yaw != kValueNotPresent)
+    muxer_projection->set_pose_yaw(parser_projection.pose_yaw);
+  if (parser_projection.pose_pitch != kValueNotPresent)
+    muxer_projection->set_pose_pitch(parser_projection.pose_pitch);
+  if (parser_projection.pose_roll != kValueNotPresent)
+    muxer_projection->set_pose_roll(parser_projection.pose_roll);
+  return true;
+}
 }  // end namespace
 
 int main(int argc, char* argv[]) {
@@ -187,6 +223,11 @@
   uint64_t pixel_width = 0;
   uint64_t pixel_height = 0;
   uint64_t stereo_mode = 0;
+  const char* projection_file = 0;
+  int64_t projection_type = mkvparser::Projection::kTypeNotPresent;
+  float projection_pose_roll = mkvparser::Projection::kValueNotPresent;
+  float projection_pose_pitch = mkvparser::Projection::kValueNotPresent;
+  float projection_pose_yaw = mkvparser::Projection::kValueNotPresent;
   int vp9_profile = -1;  // No profile set.
   int vp9_level = -1;  // No level set.
 
@@ -257,6 +298,16 @@
       pixel_height = strtol(argv[++i], &end, 10);
     } else if (!strcmp("-stereo_mode", argv[i]) && i < argc_check) {
       stereo_mode = strtol(argv[++i], &end, 10);
+    } else if (!strcmp("-projection_type", argv[i]) && i < argc_check) {
+      projection_type = strtol(argv[++i], &end, 10);
+    } else if (!strcmp("-projection_file", argv[i]) && i < argc_check) {
+      projection_file = argv[++i];
+    } else if (!strcmp("-projection_pose_roll", argv[i]) && i < argc_check) {
+      projection_pose_roll = strtof(argv[++i], &end);
+    } else if (!strcmp("-projection_pose_pitch", argv[i]) && i < argc_check) {
+      projection_pose_pitch = strtof(argv[++i], &end);
+    } else if (!strcmp("-projection_pose_yaw", argv[i]) && i < argc_check) {
+      projection_pose_yaw = strtof(argv[++i], &end);
     } else if (!strcmp("-profile", argv[i]) && i < argc_check) {
       vp9_profile = static_cast<int>(strtol(argv[++i], &end, 10));
     } else if (!strcmp("-level", argv[i]) && i < argc_check) {
@@ -422,32 +473,56 @@
           return EXIT_FAILURE;
       }
 
-      if (pVideoTrack->GetProjection()) {
+      if (pVideoTrack->GetProjection() ||
+          projection_type != mkvparser::Projection::kTypeNotPresent) {
         mkvmuxer::Projection muxer_projection;
         const mkvparser::Projection* const parser_projection =
             pVideoTrack->GetProjection();
         typedef mkvmuxer::Projection::ProjectionType MuxerProjType;
-        const int kTypeNotPresent = mkvparser::Projection::kTypeNotPresent;
-        if (parser_projection->type != kTypeNotPresent) {
-          muxer_projection.set_type(
-              static_cast<MuxerProjType>(parser_projection->type));
+        if (parser_projection &&
+            !CopyVideoProjection(*parser_projection, &muxer_projection)) {
+          printf("\n Unable to copy video projection.\n");
+          return EXIT_FAILURE;
         }
-        if (parser_projection->private_data &&
-            parser_projection->private_data_length > 0) {
-          if (!muxer_projection.SetProjectionPrivate(
-                  parser_projection->private_data,
-                  parser_projection->private_data_length)) {
+        // Override the values that came from parser if set on command line.
+        if (projection_type != mkvparser::Projection::kTypeNotPresent) {
+          muxer_projection.set_type(
+              static_cast<MuxerProjType>(projection_type));
+          if (projection_type == mkvparser::Projection::kRectangular &&
+              projection_file != NULL) {
+            printf("\n Rectangular projection must not have private data.\n");
+            return EXIT_FAILURE;
+          } else if ((projection_type == mkvparser::Projection::kCubeMap ||
+                      projection_type == mkvparser::Projection::kMesh) &&
+                     projection_file == NULL) {
+            printf("\n Mesh or CubeMap projection must have private data.\n");
             return EXIT_FAILURE;
           }
+          if (projection_file != NULL) {
+            std::string contents;
+            if (!libwebm::GetFileContents(projection_file, &contents) ||
+                contents.size() == 0) {
+              printf("\n Failed to read file \"%s\" or file is empty\n",
+                     projection_file);
+              return EXIT_FAILURE;
+            }
+            if (!muxer_projection.SetProjectionPrivate(
+                    reinterpret_cast<uint8_t*>(&contents[0]),
+                    contents.size())) {
+              printf("\n Failed to SetProjectionPrivate of length %zu.\n",
+                     contents.size());
+              return EXIT_FAILURE;
+            }
+          }
         }
-
         const float kValueNotPresent = mkvparser::Projection::kValueNotPresent;
-        if (parser_projection->pose_yaw != kValueNotPresent)
-          muxer_projection.set_pose_yaw(parser_projection->pose_yaw);
-        if (parser_projection->pose_pitch != kValueNotPresent)
-          muxer_projection.set_pose_pitch(parser_projection->pose_pitch);
-        if (parser_projection->pose_roll != kValueNotPresent)
-          muxer_projection.set_pose_roll(parser_projection->pose_roll);
+        if (projection_pose_yaw != kValueNotPresent)
+          muxer_projection.set_pose_yaw(projection_pose_yaw);
+        if (projection_pose_pitch != kValueNotPresent)
+          muxer_projection.set_pose_pitch(projection_pose_pitch);
+        if (projection_pose_roll != kValueNotPresent)
+          muxer_projection.set_pose_roll(projection_pose_roll);
+
         if (!video->SetProjection(muxer_projection))
           return EXIT_FAILURE;
       }