Internal change

PiperOrigin-RevId: 182603092
Change-Id: I852b2533e4103e0638c1031afc883bbab89bb160
diff --git a/example/muxing/camm_muxing.cc b/example/muxing/camm_muxing.cc
index ba75725..147a438 100644
--- a/example/muxing/camm_muxing.cc
+++ b/example/muxing/camm_muxing.cc
@@ -1,16 +1,25 @@
 /*
- * This code sample muxes an artificially generated video stream with a
- * data stream for camera motion metadata (CAMM) into a single mp4 file.
+ * This code sample muxes a list of jpegs with an artificially generated data
+ * stream for camera motion metadata (CAMM) into a single mp4 file.
  * The sample can be built with the "make" command.
  * After building the sample, it can be run as follows:
  *
- *    > ./camm_muxing output_file.mp4
+ *    > ./camm_muxing /path/to/frames/ num_of_frames output_file.mp4
  *
- * Note that this must be run in the sample directory as the "sample.jpg" file.
+ * /path/to/frames/ is the directory of the input jpeg files. We assume the
+ * indexing is 1-based, and the file names are
+ * 00001.jpg
+ * 00002.jpg
+ * 00003.jpg
+ * ...
  *
- * The video stream is a single JPEG file for the entire video duration. It
- * is for illustration purposes only. The calling code is expected to
- * already have the encoded bytes of video frames to mux into the mp4 file.
+ * num_of_frames is an integer that represents the number of jpegs in the
+ * directory. For example, num_of_frames = 50 means 00001.jpg to 00050.jpg in
+ * the input directory are imported in the muxing.
+ *
+ * output_file.mp4 is the output mp4 file which will consist of two streams:
+ * - A mjpeg video stream.
+ * - A stream of an artifially generated CAMM track.
  */
 
 #include <endian.h>
@@ -22,13 +31,14 @@
 #include <cstring>
 #include <fstream>
 #include <iostream>
+#include <string>
 #include <vector>
 
 #define FRAME_WIDTH 2880
 #define FRAME_HEIGHT 1800
-#define VIDEO_TIME_SECONDS 10
+#define VIDEO_FRAME_RATE 5
 #define VIDEO_TIME_SCALE 90000
-#define NUM_CAMM_SAMPLES 200
+#define CAMM_SAMPLE_RATE 200
 #define BYTE_BUFFER_SIZE 1000
 
 namespace {
@@ -206,7 +216,7 @@
   if (!MP4WriteSample(handle, video_track_id,
                       reinterpret_cast<const uint8_t *>(jpg_bytes.data()),
                       /* num_bytes */ jpg_bytes.size(),
-                      /* duration */ VIDEO_TIME_SCALE,
+                      /* duration */ VIDEO_TIME_SCALE / VIDEO_FRAME_RATE,
                       /* rendering_offset */ pts,
                       /* is_sync_sample */ true)) {
     printf("Failed to write mp4 sample to video track\n");
@@ -214,33 +224,64 @@
   }
 }
 
+static std::string GetJpegFilename(const char *dirname, int frame_index) {
+  char buffer[500];
+  snprintf(buffer, sizeof(buffer), "%s/%05d.jpg", dirname, frame_index);
+  std::string filename(buffer);
+  return filename;
+}
+
+// Reads the contents of the jpeg file into memory.
+static std::vector<char> ReadJpegFileBytes(const char *filename) {
+  struct stat buffer;
+  if (stat(filename, &buffer) != 0) {
+    printf(
+        "Sample file '%s' does not exist.\n"
+        "Make sure it exists and then run the program again.\n",
+        filename);
+    exit(1);
+  }
+  std::ifstream ifs(filename, std::ios::binary | std::ios::ate);
+  std::ifstream::pos_type pos = ifs.tellg();
+  std::vector<char> result(pos);
+  ifs.seekg(0, std::ios::beg);
+  ifs.read(&result[0], pos);
+  return result;
+}
+
 static void WriteStreams(MP4FileHandle handle, int video_track_id,
-                         const std::vector<char> &jpg_bytes,
+                         const char *dirname, int num_frames,
                          int camm_track_id) {
   char camm_buffer[BYTE_BUFFER_SIZE];
+
   int video_pts = 0;
   int camm_pts = 0;
-  int camm_packet_num = 0;
-  int max_pts = VIDEO_TIME_SECONDS * VIDEO_TIME_SCALE;
-  while (video_pts < max_pts && camm_pts < max_pts) {
+  int frame_index = 1;
+  int camm_packet_index = 0;
+
+  while (frame_index <= num_frames) {
     if (video_pts <= camm_pts) {
-      WriteVideoFrame(handle, video_track_id, jpg_bytes, video_pts,
+      std::string filename = GetJpegFilename(dirname, frame_index);
+      std::vector<char> bytes = ReadJpegFileBytes(filename.c_str());
+      WriteVideoFrame(handle, video_track_id, bytes, video_pts,
                       VIDEO_TIME_SCALE);
-      video_pts += VIDEO_TIME_SCALE;
+      video_pts += VIDEO_TIME_SCALE / VIDEO_FRAME_RATE;
+      frame_index++;
     } else {
-      WriteCammPacket(handle, camm_track_id, camm_pts, camm_packet_num,
+      WriteCammPacket(handle, camm_track_id, camm_pts, camm_packet_index,
                       camm_buffer);
-      camm_pts += max_pts / NUM_CAMM_SAMPLES;
-      camm_packet_num++;
+      camm_pts += VIDEO_TIME_SCALE / CAMM_SAMPLE_RATE;
+      camm_packet_index++;
     }
   }
 }
 
-static int AddVideoTrack(MP4FileHandle handle) {
+static int AddVideoTrack(MP4FileHandle handle, int num_frames) {
   printf("Adding video track\n");
-  int video_track_id = MP4AddVideoTrack(
-      handle, VIDEO_TIME_SCALE, VIDEO_TIME_SCALE * VIDEO_TIME_SECONDS,
-      FRAME_WIDTH, FRAME_HEIGHT, MP4_JPEG_VIDEO_TYPE);
+  int video_track_id =
+      MP4AddVideoTrack(handle, VIDEO_TIME_SCALE,
+                       VIDEO_TIME_SCALE * num_frames / VIDEO_FRAME_RATE,
+                       FRAME_WIDTH, FRAME_HEIGHT, MP4_JPEG_VIDEO_TYPE);
   if (video_track_id == MP4_INVALID_TRACK_ID) {
     printf("Can't add video track\n");
     exit(1);
@@ -262,29 +303,13 @@
   return data_track_id;
 }
 
-// Reads the contents of the sample jpeg file into memory.
-static std::vector<char> ReadSampleFileBytes() {
-  struct stat buffer;
-  const char *filename = "sample.jpg";
-  if (stat(filename, &buffer) != 0) {
-    printf(
-        "Sample file 'sample.jpg' doesn't exist\n"
-        "Make sure it is in the directory and then run the program\n"
-        "again.\n");
-    exit(1);
-  }
-  std::ifstream ifs(filename, std::ios::binary | std::ios::ate);
-  std::ifstream::pos_type pos = ifs.tellg();
-  std::vector<char> result(pos);
-  ifs.seekg(0, std::ios::beg);
-  ifs.read(&result[0], pos);
-  return result;
-}
-
 static void VerifyProgramArgs(int argc, char **argv) {
-  if (argc != 2) {
+  if (argc != 4) {
     printf(
-        "Usage: %s file.mp4\n"
+        "Usage: %s frames/ 50 file.mp4\n"
+        "frames/ is the input directory of frames\n"
+        "50 is the number of frames in the input directory to put in the "
+        "video, i.e. 00001.jpg to 00050.jpg\n"
         "file.mp4 is the output location of the generated video\n",
         argv[0]);
     exit(1);
@@ -302,12 +327,12 @@
 #endif
 
   VerifyProgramArgs(argc, argv);
-  std::vector<char> jpg_bytes = ReadSampleFileBytes();
-  MP4FileHandle handle = MP4Create(argv[1], /* flags */ 0);
-  int video_track_id = AddVideoTrack(handle);
+  MP4FileHandle handle = MP4Create(argv[3], /* flags */ 0);
+  int num_frames = std::stoi(argv[2]);
+  int video_track_id = AddVideoTrack(handle, num_frames);
   int camm_track_id = AddCammTrack(handle);
 
-  WriteStreams(handle, video_track_id, jpg_bytes, camm_track_id);
+  WriteStreams(handle, video_track_id, argv[1], num_frames, camm_track_id);
 
   printf("Dumping MP4 file information:\n");
   MP4Dump(handle);
diff --git a/example/muxing/sample.jpg b/example/muxing/sample.jpg
deleted file mode 100644
index c76d552..0000000
--- a/example/muxing/sample.jpg
+++ /dev/null
Binary files differ