1*103e46e4SHarish Mahendrakar // Copyright (c) 2011 The WebM project authors. All Rights Reserved.
2*103e46e4SHarish Mahendrakar //
3*103e46e4SHarish Mahendrakar // Use of this source code is governed by a BSD-style license
4*103e46e4SHarish Mahendrakar // that can be found in the LICENSE file in the root of the source
5*103e46e4SHarish Mahendrakar // tree. An additional intellectual property rights grant can be found
6*103e46e4SHarish Mahendrakar // in the file PATENTS. All contributing project authors may
7*103e46e4SHarish Mahendrakar // be found in the AUTHORS file in the root of the source tree.
8*103e46e4SHarish Mahendrakar #include <stdint.h>
9*103e46e4SHarish Mahendrakar
10*103e46e4SHarish Mahendrakar #include <cstdio>
11*103e46e4SHarish Mahendrakar #include <cstdlib>
12*103e46e4SHarish Mahendrakar #include <cstring>
13*103e46e4SHarish Mahendrakar #include <list>
14*103e46e4SHarish Mahendrakar #include <memory>
15*103e46e4SHarish Mahendrakar #include <string>
16*103e46e4SHarish Mahendrakar
17*103e46e4SHarish Mahendrakar // libwebm common includes.
18*103e46e4SHarish Mahendrakar #include "common/file_util.h"
19*103e46e4SHarish Mahendrakar #include "common/hdr_util.h"
20*103e46e4SHarish Mahendrakar
21*103e46e4SHarish Mahendrakar // libwebm mkvparser includes
22*103e46e4SHarish Mahendrakar #include "mkvparser/mkvparser.h"
23*103e46e4SHarish Mahendrakar #include "mkvparser/mkvreader.h"
24*103e46e4SHarish Mahendrakar
25*103e46e4SHarish Mahendrakar // libwebm mkvmuxer includes
26*103e46e4SHarish Mahendrakar #include "mkvmuxer/mkvmuxer.h"
27*103e46e4SHarish Mahendrakar #include "mkvmuxer/mkvmuxertypes.h"
28*103e46e4SHarish Mahendrakar #include "mkvmuxer/mkvwriter.h"
29*103e46e4SHarish Mahendrakar
30*103e46e4SHarish Mahendrakar #include "sample_muxer_metadata.h"
31*103e46e4SHarish Mahendrakar
32*103e46e4SHarish Mahendrakar namespace {
33*103e46e4SHarish Mahendrakar
Usage()34*103e46e4SHarish Mahendrakar void Usage() {
35*103e46e4SHarish Mahendrakar printf("Usage: mkvmuxer_sample -i input -o output [options]\n");
36*103e46e4SHarish Mahendrakar printf("\n");
37*103e46e4SHarish Mahendrakar printf("Main options:\n");
38*103e46e4SHarish Mahendrakar printf(" -h | -? show help\n");
39*103e46e4SHarish Mahendrakar printf(" -video <int> >0 outputs video\n");
40*103e46e4SHarish Mahendrakar printf(" -audio <int> >0 outputs audio\n");
41*103e46e4SHarish Mahendrakar printf(" -live <int> >0 puts the muxer into live mode\n");
42*103e46e4SHarish Mahendrakar printf(" 0 puts the muxer into file mode\n");
43*103e46e4SHarish Mahendrakar printf(" -output_cues <int> >0 outputs cues element\n");
44*103e46e4SHarish Mahendrakar printf(" -cues_on_video_track <int> >0 outputs cues on video track\n");
45*103e46e4SHarish Mahendrakar printf(" -cues_on_audio_track <int> >0 outputs cues on audio track\n");
46*103e46e4SHarish Mahendrakar printf(" -max_cluster_duration <double> in seconds\n");
47*103e46e4SHarish Mahendrakar printf(" -max_cluster_size <int> in bytes\n");
48*103e46e4SHarish Mahendrakar printf(" -switch_tracks <int> >0 switches tracks in output\n");
49*103e46e4SHarish Mahendrakar printf(" -audio_track_number <int> >0 Changes the audio track number\n");
50*103e46e4SHarish Mahendrakar printf(" -video_track_number <int> >0 Changes the video track number\n");
51*103e46e4SHarish Mahendrakar printf(" -chunking <string> Chunk output\n");
52*103e46e4SHarish Mahendrakar printf(" -copy_tags <int> >0 Copies the tags\n");
53*103e46e4SHarish Mahendrakar printf(" -accurate_cluster_duration <int> ");
54*103e46e4SHarish Mahendrakar printf(">0 Writes the last frame in each cluster with Duration\n");
55*103e46e4SHarish Mahendrakar printf(" -fixed_size_cluster_timecode <int> ");
56*103e46e4SHarish Mahendrakar printf(">0 Writes the cluster timecode using exactly 8 bytes\n");
57*103e46e4SHarish Mahendrakar printf(" -copy_input_duration >0 Copies the input duration\n");
58*103e46e4SHarish Mahendrakar printf("\n");
59*103e46e4SHarish Mahendrakar printf("Video options:\n");
60*103e46e4SHarish Mahendrakar printf(" -display_width <int> Display width in pixels\n");
61*103e46e4SHarish Mahendrakar printf(" -display_height <int> Display height in pixels\n");
62*103e46e4SHarish Mahendrakar printf(" -pixel_width <int> Override pixel width\n");
63*103e46e4SHarish Mahendrakar printf(" -pixel_height <int> Override pixel height\n");
64*103e46e4SHarish Mahendrakar printf(" -projection_type <int> Set/override projection type:\n");
65*103e46e4SHarish Mahendrakar printf(" 0: Rectangular\n");
66*103e46e4SHarish Mahendrakar printf(" 1: Equirectangular\n");
67*103e46e4SHarish Mahendrakar printf(" 2: Cube map\n");
68*103e46e4SHarish Mahendrakar printf(" 3: Mesh\n");
69*103e46e4SHarish Mahendrakar printf(" -projection_file <string> Override projection private data\n");
70*103e46e4SHarish Mahendrakar printf(" with contents of this file\n");
71*103e46e4SHarish Mahendrakar printf(" -projection_pose_yaw <float> Projection pose yaw\n");
72*103e46e4SHarish Mahendrakar printf(" -projection_pose_pitch <float> Projection pose pitch\n");
73*103e46e4SHarish Mahendrakar printf(" -projection_pose_roll <float> Projection pose roll\n");
74*103e46e4SHarish Mahendrakar printf(" -stereo_mode <int> 3D video mode\n");
75*103e46e4SHarish Mahendrakar printf("\n");
76*103e46e4SHarish Mahendrakar printf("VP9 options:\n");
77*103e46e4SHarish Mahendrakar printf(" -profile <int> VP9 profile\n");
78*103e46e4SHarish Mahendrakar printf(" -level <int> VP9 level\n");
79*103e46e4SHarish Mahendrakar printf("\n");
80*103e46e4SHarish Mahendrakar printf("Cues options:\n");
81*103e46e4SHarish Mahendrakar printf(" -output_cues_block_number <int> >0 outputs cue block number\n");
82*103e46e4SHarish Mahendrakar printf(" -cues_before_clusters <int> >0 puts Cues before Clusters\n");
83*103e46e4SHarish Mahendrakar printf("\n");
84*103e46e4SHarish Mahendrakar printf("Metadata options:\n");
85*103e46e4SHarish Mahendrakar printf(" -webvtt-subtitles <vttfile> ");
86*103e46e4SHarish Mahendrakar printf("add WebVTT subtitles as metadata track\n");
87*103e46e4SHarish Mahendrakar printf(" -webvtt-captions <vttfile> ");
88*103e46e4SHarish Mahendrakar printf("add WebVTT captions as metadata track\n");
89*103e46e4SHarish Mahendrakar printf(" -webvtt-descriptions <vttfile> ");
90*103e46e4SHarish Mahendrakar printf("add WebVTT descriptions as metadata track\n");
91*103e46e4SHarish Mahendrakar printf(" -webvtt-metadata <vttfile> ");
92*103e46e4SHarish Mahendrakar printf("add WebVTT subtitles as metadata track\n");
93*103e46e4SHarish Mahendrakar printf(" -webvtt-chapters <vttfile> ");
94*103e46e4SHarish Mahendrakar printf("add WebVTT chapters as MKV chapters element\n");
95*103e46e4SHarish Mahendrakar }
96*103e46e4SHarish Mahendrakar
97*103e46e4SHarish Mahendrakar struct MetadataFile {
98*103e46e4SHarish Mahendrakar const char* name;
99*103e46e4SHarish Mahendrakar SampleMuxerMetadata::Kind kind;
100*103e46e4SHarish Mahendrakar };
101*103e46e4SHarish Mahendrakar
102*103e46e4SHarish Mahendrakar typedef std::list<MetadataFile> metadata_files_t;
103*103e46e4SHarish Mahendrakar
104*103e46e4SHarish Mahendrakar // Cache the WebVTT filenames specified as command-line args.
LoadMetadataFiles(const metadata_files_t & files,SampleMuxerMetadata * metadata)105*103e46e4SHarish Mahendrakar bool LoadMetadataFiles(const metadata_files_t& files,
106*103e46e4SHarish Mahendrakar SampleMuxerMetadata* metadata) {
107*103e46e4SHarish Mahendrakar typedef metadata_files_t::const_iterator iter_t;
108*103e46e4SHarish Mahendrakar
109*103e46e4SHarish Mahendrakar iter_t i = files.begin();
110*103e46e4SHarish Mahendrakar const iter_t j = files.end();
111*103e46e4SHarish Mahendrakar
112*103e46e4SHarish Mahendrakar while (i != j) {
113*103e46e4SHarish Mahendrakar const metadata_files_t::value_type& v = *i++;
114*103e46e4SHarish Mahendrakar
115*103e46e4SHarish Mahendrakar if (!metadata->Load(v.name, v.kind))
116*103e46e4SHarish Mahendrakar return false;
117*103e46e4SHarish Mahendrakar }
118*103e46e4SHarish Mahendrakar
119*103e46e4SHarish Mahendrakar return true;
120*103e46e4SHarish Mahendrakar }
121*103e46e4SHarish Mahendrakar
ParseArgWebVTT(char * argv[],int * argv_index,int argc_check,metadata_files_t * metadata_files)122*103e46e4SHarish Mahendrakar int ParseArgWebVTT(char* argv[], int* argv_index, int argc_check,
123*103e46e4SHarish Mahendrakar metadata_files_t* metadata_files) {
124*103e46e4SHarish Mahendrakar int& i = *argv_index;
125*103e46e4SHarish Mahendrakar
126*103e46e4SHarish Mahendrakar enum { kCount = 5 };
127*103e46e4SHarish Mahendrakar struct Arg {
128*103e46e4SHarish Mahendrakar const char* name;
129*103e46e4SHarish Mahendrakar SampleMuxerMetadata::Kind kind;
130*103e46e4SHarish Mahendrakar };
131*103e46e4SHarish Mahendrakar const Arg args[kCount] = {
132*103e46e4SHarish Mahendrakar {"-webvtt-subtitles", SampleMuxerMetadata::kSubtitles},
133*103e46e4SHarish Mahendrakar {"-webvtt-captions", SampleMuxerMetadata::kCaptions},
134*103e46e4SHarish Mahendrakar {"-webvtt-descriptions", SampleMuxerMetadata::kDescriptions},
135*103e46e4SHarish Mahendrakar {"-webvtt-metadata", SampleMuxerMetadata::kMetadata},
136*103e46e4SHarish Mahendrakar {"-webvtt-chapters", SampleMuxerMetadata::kChapters}};
137*103e46e4SHarish Mahendrakar
138*103e46e4SHarish Mahendrakar for (int idx = 0; idx < kCount; ++idx) {
139*103e46e4SHarish Mahendrakar const Arg& arg = args[idx];
140*103e46e4SHarish Mahendrakar
141*103e46e4SHarish Mahendrakar if (strcmp(arg.name, argv[i]) != 0) // no match
142*103e46e4SHarish Mahendrakar continue;
143*103e46e4SHarish Mahendrakar
144*103e46e4SHarish Mahendrakar ++i; // consume arg name here
145*103e46e4SHarish Mahendrakar
146*103e46e4SHarish Mahendrakar if (i > argc_check) {
147*103e46e4SHarish Mahendrakar printf("missing value for %s\n", arg.name);
148*103e46e4SHarish Mahendrakar return -1; // error
149*103e46e4SHarish Mahendrakar }
150*103e46e4SHarish Mahendrakar
151*103e46e4SHarish Mahendrakar MetadataFile f;
152*103e46e4SHarish Mahendrakar f.name = argv[i]; // arg value is consumed via caller's loop idx
153*103e46e4SHarish Mahendrakar f.kind = arg.kind;
154*103e46e4SHarish Mahendrakar
155*103e46e4SHarish Mahendrakar metadata_files->push_back(f);
156*103e46e4SHarish Mahendrakar return 1; // successfully parsed WebVTT arg
157*103e46e4SHarish Mahendrakar }
158*103e46e4SHarish Mahendrakar
159*103e46e4SHarish Mahendrakar return 0; // not a WebVTT arg
160*103e46e4SHarish Mahendrakar }
161*103e46e4SHarish Mahendrakar
CopyVideoProjection(const mkvparser::Projection & parser_projection,mkvmuxer::Projection * muxer_projection)162*103e46e4SHarish Mahendrakar bool CopyVideoProjection(const mkvparser::Projection& parser_projection,
163*103e46e4SHarish Mahendrakar mkvmuxer::Projection* muxer_projection) {
164*103e46e4SHarish Mahendrakar typedef mkvmuxer::Projection::ProjectionType MuxerProjType;
165*103e46e4SHarish Mahendrakar const int kTypeNotPresent = mkvparser::Projection::kTypeNotPresent;
166*103e46e4SHarish Mahendrakar if (parser_projection.type != kTypeNotPresent) {
167*103e46e4SHarish Mahendrakar muxer_projection->set_type(
168*103e46e4SHarish Mahendrakar static_cast<MuxerProjType>(parser_projection.type));
169*103e46e4SHarish Mahendrakar }
170*103e46e4SHarish Mahendrakar if (parser_projection.private_data &&
171*103e46e4SHarish Mahendrakar parser_projection.private_data_length > 0) {
172*103e46e4SHarish Mahendrakar if (!muxer_projection->SetProjectionPrivate(
173*103e46e4SHarish Mahendrakar parser_projection.private_data,
174*103e46e4SHarish Mahendrakar parser_projection.private_data_length)) {
175*103e46e4SHarish Mahendrakar return false;
176*103e46e4SHarish Mahendrakar }
177*103e46e4SHarish Mahendrakar }
178*103e46e4SHarish Mahendrakar
179*103e46e4SHarish Mahendrakar const float kValueNotPresent = mkvparser::Projection::kValueNotPresent;
180*103e46e4SHarish Mahendrakar if (parser_projection.pose_yaw != kValueNotPresent)
181*103e46e4SHarish Mahendrakar muxer_projection->set_pose_yaw(parser_projection.pose_yaw);
182*103e46e4SHarish Mahendrakar if (parser_projection.pose_pitch != kValueNotPresent)
183*103e46e4SHarish Mahendrakar muxer_projection->set_pose_pitch(parser_projection.pose_pitch);
184*103e46e4SHarish Mahendrakar if (parser_projection.pose_roll != kValueNotPresent)
185*103e46e4SHarish Mahendrakar muxer_projection->set_pose_roll(parser_projection.pose_roll);
186*103e46e4SHarish Mahendrakar return true;
187*103e46e4SHarish Mahendrakar }
188*103e46e4SHarish Mahendrakar } // end namespace
189*103e46e4SHarish Mahendrakar
main(int argc,char * argv[])190*103e46e4SHarish Mahendrakar int main(int argc, char* argv[]) {
191*103e46e4SHarish Mahendrakar char* input = NULL;
192*103e46e4SHarish Mahendrakar char* output = NULL;
193*103e46e4SHarish Mahendrakar
194*103e46e4SHarish Mahendrakar // Segment variables
195*103e46e4SHarish Mahendrakar bool output_video = true;
196*103e46e4SHarish Mahendrakar bool output_audio = true;
197*103e46e4SHarish Mahendrakar bool live_mode = false;
198*103e46e4SHarish Mahendrakar bool output_cues = true;
199*103e46e4SHarish Mahendrakar bool cues_before_clusters = false;
200*103e46e4SHarish Mahendrakar bool cues_on_video_track = true;
201*103e46e4SHarish Mahendrakar bool cues_on_audio_track = false;
202*103e46e4SHarish Mahendrakar uint64_t max_cluster_duration = 0;
203*103e46e4SHarish Mahendrakar uint64_t max_cluster_size = 0;
204*103e46e4SHarish Mahendrakar bool switch_tracks = false;
205*103e46e4SHarish Mahendrakar int audio_track_number = 0; // 0 tells muxer to decide.
206*103e46e4SHarish Mahendrakar int video_track_number = 0; // 0 tells muxer to decide.
207*103e46e4SHarish Mahendrakar bool chunking = false;
208*103e46e4SHarish Mahendrakar bool copy_tags = false;
209*103e46e4SHarish Mahendrakar const char* chunk_name = NULL;
210*103e46e4SHarish Mahendrakar bool accurate_cluster_duration = false;
211*103e46e4SHarish Mahendrakar bool fixed_size_cluster_timecode = false;
212*103e46e4SHarish Mahendrakar bool copy_input_duration = false;
213*103e46e4SHarish Mahendrakar
214*103e46e4SHarish Mahendrakar bool output_cues_block_number = true;
215*103e46e4SHarish Mahendrakar
216*103e46e4SHarish Mahendrakar uint64_t display_width = 0;
217*103e46e4SHarish Mahendrakar uint64_t display_height = 0;
218*103e46e4SHarish Mahendrakar uint64_t pixel_width = 0;
219*103e46e4SHarish Mahendrakar uint64_t pixel_height = 0;
220*103e46e4SHarish Mahendrakar uint64_t stereo_mode = 0;
221*103e46e4SHarish Mahendrakar const char* projection_file = 0;
222*103e46e4SHarish Mahendrakar int64_t projection_type = mkvparser::Projection::kTypeNotPresent;
223*103e46e4SHarish Mahendrakar float projection_pose_roll = mkvparser::Projection::kValueNotPresent;
224*103e46e4SHarish Mahendrakar float projection_pose_pitch = mkvparser::Projection::kValueNotPresent;
225*103e46e4SHarish Mahendrakar float projection_pose_yaw = mkvparser::Projection::kValueNotPresent;
226*103e46e4SHarish Mahendrakar int vp9_profile = -1; // No profile set.
227*103e46e4SHarish Mahendrakar int vp9_level = -1; // No level set.
228*103e46e4SHarish Mahendrakar
229*103e46e4SHarish Mahendrakar metadata_files_t metadata_files;
230*103e46e4SHarish Mahendrakar
231*103e46e4SHarish Mahendrakar const int argc_check = argc - 1;
232*103e46e4SHarish Mahendrakar for (int i = 1; i < argc; ++i) {
233*103e46e4SHarish Mahendrakar char* end;
234*103e46e4SHarish Mahendrakar
235*103e46e4SHarish Mahendrakar if (!strcmp("-h", argv[i]) || !strcmp("-?", argv[i])) {
236*103e46e4SHarish Mahendrakar Usage();
237*103e46e4SHarish Mahendrakar return EXIT_SUCCESS;
238*103e46e4SHarish Mahendrakar } else if (!strcmp("-i", argv[i]) && i < argc_check) {
239*103e46e4SHarish Mahendrakar input = argv[++i];
240*103e46e4SHarish Mahendrakar } else if (!strcmp("-o", argv[i]) && i < argc_check) {
241*103e46e4SHarish Mahendrakar output = argv[++i];
242*103e46e4SHarish Mahendrakar } else if (!strcmp("-video", argv[i]) && i < argc_check) {
243*103e46e4SHarish Mahendrakar output_video = strtol(argv[++i], &end, 10) == 0 ? false : true;
244*103e46e4SHarish Mahendrakar } else if (!strcmp("-audio", argv[i]) && i < argc_check) {
245*103e46e4SHarish Mahendrakar output_audio = strtol(argv[++i], &end, 10) == 0 ? false : true;
246*103e46e4SHarish Mahendrakar } else if (!strcmp("-live", argv[i]) && i < argc_check) {
247*103e46e4SHarish Mahendrakar live_mode = strtol(argv[++i], &end, 10) == 0 ? false : true;
248*103e46e4SHarish Mahendrakar } else if (!strcmp("-output_cues", argv[i]) && i < argc_check) {
249*103e46e4SHarish Mahendrakar output_cues = strtol(argv[++i], &end, 10) == 0 ? false : true;
250*103e46e4SHarish Mahendrakar } else if (!strcmp("-cues_before_clusters", argv[i]) && i < argc_check) {
251*103e46e4SHarish Mahendrakar cues_before_clusters = strtol(argv[++i], &end, 10) == 0 ? false : true;
252*103e46e4SHarish Mahendrakar } else if (!strcmp("-cues_on_video_track", argv[i]) && i < argc_check) {
253*103e46e4SHarish Mahendrakar cues_on_video_track = strtol(argv[++i], &end, 10) == 0 ? false : true;
254*103e46e4SHarish Mahendrakar if (cues_on_video_track)
255*103e46e4SHarish Mahendrakar cues_on_audio_track = false;
256*103e46e4SHarish Mahendrakar } else if (!strcmp("-cues_on_audio_track", argv[i]) && i < argc_check) {
257*103e46e4SHarish Mahendrakar cues_on_audio_track = strtol(argv[++i], &end, 10) == 0 ? false : true;
258*103e46e4SHarish Mahendrakar if (cues_on_audio_track)
259*103e46e4SHarish Mahendrakar cues_on_video_track = false;
260*103e46e4SHarish Mahendrakar } else if (!strcmp("-max_cluster_duration", argv[i]) && i < argc_check) {
261*103e46e4SHarish Mahendrakar const double seconds = strtod(argv[++i], &end);
262*103e46e4SHarish Mahendrakar max_cluster_duration = static_cast<uint64_t>(seconds * 1000000000.0);
263*103e46e4SHarish Mahendrakar } else if (!strcmp("-max_cluster_size", argv[i]) && i < argc_check) {
264*103e46e4SHarish Mahendrakar max_cluster_size = strtol(argv[++i], &end, 10);
265*103e46e4SHarish Mahendrakar } else if (!strcmp("-switch_tracks", argv[i]) && i < argc_check) {
266*103e46e4SHarish Mahendrakar switch_tracks = strtol(argv[++i], &end, 10) == 0 ? false : true;
267*103e46e4SHarish Mahendrakar } else if (!strcmp("-audio_track_number", argv[i]) && i < argc_check) {
268*103e46e4SHarish Mahendrakar audio_track_number = static_cast<int>(strtol(argv[++i], &end, 10));
269*103e46e4SHarish Mahendrakar } else if (!strcmp("-video_track_number", argv[i]) && i < argc_check) {
270*103e46e4SHarish Mahendrakar video_track_number = static_cast<int>(strtol(argv[++i], &end, 10));
271*103e46e4SHarish Mahendrakar } else if (!strcmp("-chunking", argv[i]) && i < argc_check) {
272*103e46e4SHarish Mahendrakar chunking = true;
273*103e46e4SHarish Mahendrakar chunk_name = argv[++i];
274*103e46e4SHarish Mahendrakar } else if (!strcmp("-copy_tags", argv[i]) && i < argc_check) {
275*103e46e4SHarish Mahendrakar copy_tags = strtol(argv[++i], &end, 10) == 0 ? false : true;
276*103e46e4SHarish Mahendrakar } else if (!strcmp("-accurate_cluster_duration", argv[i]) &&
277*103e46e4SHarish Mahendrakar i < argc_check) {
278*103e46e4SHarish Mahendrakar accurate_cluster_duration =
279*103e46e4SHarish Mahendrakar strtol(argv[++i], &end, 10) == 0 ? false : true;
280*103e46e4SHarish Mahendrakar } else if (!strcmp("-fixed_size_cluster_timecode", argv[i]) &&
281*103e46e4SHarish Mahendrakar i < argc_check) {
282*103e46e4SHarish Mahendrakar fixed_size_cluster_timecode =
283*103e46e4SHarish Mahendrakar strtol(argv[++i], &end, 10) == 0 ? false : true;
284*103e46e4SHarish Mahendrakar } else if (!strcmp("-copy_input_duration", argv[i]) && i < argc_check) {
285*103e46e4SHarish Mahendrakar copy_input_duration = strtol(argv[++i], &end, 10) == 0 ? false : true;
286*103e46e4SHarish Mahendrakar } else if (!strcmp("-display_width", argv[i]) && i < argc_check) {
287*103e46e4SHarish Mahendrakar display_width = strtol(argv[++i], &end, 10);
288*103e46e4SHarish Mahendrakar } else if (!strcmp("-display_height", argv[i]) && i < argc_check) {
289*103e46e4SHarish Mahendrakar display_height = strtol(argv[++i], &end, 10);
290*103e46e4SHarish Mahendrakar } else if (!strcmp("-pixel_width", argv[i]) && i < argc_check) {
291*103e46e4SHarish Mahendrakar pixel_width = strtol(argv[++i], &end, 10);
292*103e46e4SHarish Mahendrakar } else if (!strcmp("-pixel_height", argv[i]) && i < argc_check) {
293*103e46e4SHarish Mahendrakar pixel_height = strtol(argv[++i], &end, 10);
294*103e46e4SHarish Mahendrakar } else if (!strcmp("-stereo_mode", argv[i]) && i < argc_check) {
295*103e46e4SHarish Mahendrakar stereo_mode = strtol(argv[++i], &end, 10);
296*103e46e4SHarish Mahendrakar } else if (!strcmp("-projection_type", argv[i]) && i < argc_check) {
297*103e46e4SHarish Mahendrakar projection_type = strtol(argv[++i], &end, 10);
298*103e46e4SHarish Mahendrakar } else if (!strcmp("-projection_file", argv[i]) && i < argc_check) {
299*103e46e4SHarish Mahendrakar projection_file = argv[++i];
300*103e46e4SHarish Mahendrakar } else if (!strcmp("-projection_pose_roll", argv[i]) && i < argc_check) {
301*103e46e4SHarish Mahendrakar projection_pose_roll = strtof(argv[++i], &end);
302*103e46e4SHarish Mahendrakar } else if (!strcmp("-projection_pose_pitch", argv[i]) && i < argc_check) {
303*103e46e4SHarish Mahendrakar projection_pose_pitch = strtof(argv[++i], &end);
304*103e46e4SHarish Mahendrakar } else if (!strcmp("-projection_pose_yaw", argv[i]) && i < argc_check) {
305*103e46e4SHarish Mahendrakar projection_pose_yaw = strtof(argv[++i], &end);
306*103e46e4SHarish Mahendrakar } else if (!strcmp("-profile", argv[i]) && i < argc_check) {
307*103e46e4SHarish Mahendrakar vp9_profile = static_cast<int>(strtol(argv[++i], &end, 10));
308*103e46e4SHarish Mahendrakar } else if (!strcmp("-level", argv[i]) && i < argc_check) {
309*103e46e4SHarish Mahendrakar vp9_level = static_cast<int>(strtol(argv[++i], &end, 10));
310*103e46e4SHarish Mahendrakar } else if (!strcmp("-output_cues_block_number", argv[i]) &&
311*103e46e4SHarish Mahendrakar i < argc_check) {
312*103e46e4SHarish Mahendrakar output_cues_block_number =
313*103e46e4SHarish Mahendrakar strtol(argv[++i], &end, 10) == 0 ? false : true;
314*103e46e4SHarish Mahendrakar } else if (int e = ParseArgWebVTT(argv, &i, argc_check, &metadata_files)) {
315*103e46e4SHarish Mahendrakar if (e < 0)
316*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
317*103e46e4SHarish Mahendrakar }
318*103e46e4SHarish Mahendrakar }
319*103e46e4SHarish Mahendrakar
320*103e46e4SHarish Mahendrakar if (input == NULL || output == NULL) {
321*103e46e4SHarish Mahendrakar Usage();
322*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
323*103e46e4SHarish Mahendrakar }
324*103e46e4SHarish Mahendrakar
325*103e46e4SHarish Mahendrakar // Get parser header info
326*103e46e4SHarish Mahendrakar mkvparser::MkvReader reader;
327*103e46e4SHarish Mahendrakar
328*103e46e4SHarish Mahendrakar if (reader.Open(input)) {
329*103e46e4SHarish Mahendrakar printf("\n Filename is invalid or error while opening.\n");
330*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
331*103e46e4SHarish Mahendrakar }
332*103e46e4SHarish Mahendrakar
333*103e46e4SHarish Mahendrakar long long pos = 0;
334*103e46e4SHarish Mahendrakar mkvparser::EBMLHeader ebml_header;
335*103e46e4SHarish Mahendrakar long long ret = ebml_header.Parse(&reader, pos);
336*103e46e4SHarish Mahendrakar if (ret) {
337*103e46e4SHarish Mahendrakar printf("\n EBMLHeader::Parse() failed.");
338*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
339*103e46e4SHarish Mahendrakar }
340*103e46e4SHarish Mahendrakar
341*103e46e4SHarish Mahendrakar mkvparser::Segment* parser_segment_;
342*103e46e4SHarish Mahendrakar ret = mkvparser::Segment::CreateInstance(&reader, pos, parser_segment_);
343*103e46e4SHarish Mahendrakar if (ret) {
344*103e46e4SHarish Mahendrakar printf("\n Segment::CreateInstance() failed.");
345*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
346*103e46e4SHarish Mahendrakar }
347*103e46e4SHarish Mahendrakar
348*103e46e4SHarish Mahendrakar const std::unique_ptr<mkvparser::Segment> parser_segment(parser_segment_);
349*103e46e4SHarish Mahendrakar ret = parser_segment->Load();
350*103e46e4SHarish Mahendrakar if (ret < 0) {
351*103e46e4SHarish Mahendrakar printf("\n Segment::Load() failed.");
352*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
353*103e46e4SHarish Mahendrakar }
354*103e46e4SHarish Mahendrakar
355*103e46e4SHarish Mahendrakar const mkvparser::SegmentInfo* const segment_info = parser_segment->GetInfo();
356*103e46e4SHarish Mahendrakar if (segment_info == NULL) {
357*103e46e4SHarish Mahendrakar printf("\n Segment::GetInfo() failed.");
358*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
359*103e46e4SHarish Mahendrakar }
360*103e46e4SHarish Mahendrakar const long long timeCodeScale = segment_info->GetTimeCodeScale();
361*103e46e4SHarish Mahendrakar
362*103e46e4SHarish Mahendrakar // Set muxer header info
363*103e46e4SHarish Mahendrakar mkvmuxer::MkvWriter writer;
364*103e46e4SHarish Mahendrakar
365*103e46e4SHarish Mahendrakar const std::string temp_file =
366*103e46e4SHarish Mahendrakar cues_before_clusters ? libwebm::GetTempFileName() : output;
367*103e46e4SHarish Mahendrakar if (!writer.Open(temp_file.c_str())) {
368*103e46e4SHarish Mahendrakar printf("\n Filename is invalid or error while opening.\n");
369*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
370*103e46e4SHarish Mahendrakar }
371*103e46e4SHarish Mahendrakar
372*103e46e4SHarish Mahendrakar // Set Segment element attributes
373*103e46e4SHarish Mahendrakar mkvmuxer::Segment muxer_segment;
374*103e46e4SHarish Mahendrakar
375*103e46e4SHarish Mahendrakar if (!muxer_segment.Init(&writer)) {
376*103e46e4SHarish Mahendrakar printf("\n Could not initialize muxer segment!\n");
377*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
378*103e46e4SHarish Mahendrakar }
379*103e46e4SHarish Mahendrakar
380*103e46e4SHarish Mahendrakar muxer_segment.AccurateClusterDuration(accurate_cluster_duration);
381*103e46e4SHarish Mahendrakar muxer_segment.UseFixedSizeClusterTimecode(fixed_size_cluster_timecode);
382*103e46e4SHarish Mahendrakar
383*103e46e4SHarish Mahendrakar if (live_mode)
384*103e46e4SHarish Mahendrakar muxer_segment.set_mode(mkvmuxer::Segment::kLive);
385*103e46e4SHarish Mahendrakar else
386*103e46e4SHarish Mahendrakar muxer_segment.set_mode(mkvmuxer::Segment::kFile);
387*103e46e4SHarish Mahendrakar
388*103e46e4SHarish Mahendrakar if (chunking)
389*103e46e4SHarish Mahendrakar muxer_segment.SetChunking(true, chunk_name);
390*103e46e4SHarish Mahendrakar
391*103e46e4SHarish Mahendrakar if (max_cluster_duration > 0)
392*103e46e4SHarish Mahendrakar muxer_segment.set_max_cluster_duration(max_cluster_duration);
393*103e46e4SHarish Mahendrakar if (max_cluster_size > 0)
394*103e46e4SHarish Mahendrakar muxer_segment.set_max_cluster_size(max_cluster_size);
395*103e46e4SHarish Mahendrakar muxer_segment.OutputCues(output_cues);
396*103e46e4SHarish Mahendrakar
397*103e46e4SHarish Mahendrakar // Set SegmentInfo element attributes
398*103e46e4SHarish Mahendrakar mkvmuxer::SegmentInfo* const info = muxer_segment.GetSegmentInfo();
399*103e46e4SHarish Mahendrakar info->set_timecode_scale(timeCodeScale);
400*103e46e4SHarish Mahendrakar info->set_writing_app("mkvmuxer_sample");
401*103e46e4SHarish Mahendrakar
402*103e46e4SHarish Mahendrakar const mkvparser::Tags* const tags = parser_segment->GetTags();
403*103e46e4SHarish Mahendrakar if (copy_tags && tags) {
404*103e46e4SHarish Mahendrakar for (int i = 0; i < tags->GetTagCount(); i++) {
405*103e46e4SHarish Mahendrakar const mkvparser::Tags::Tag* const tag = tags->GetTag(i);
406*103e46e4SHarish Mahendrakar mkvmuxer::Tag* muxer_tag = muxer_segment.AddTag();
407*103e46e4SHarish Mahendrakar
408*103e46e4SHarish Mahendrakar for (int j = 0; j < tag->GetSimpleTagCount(); j++) {
409*103e46e4SHarish Mahendrakar const mkvparser::Tags::SimpleTag* const simple_tag =
410*103e46e4SHarish Mahendrakar tag->GetSimpleTag(j);
411*103e46e4SHarish Mahendrakar muxer_tag->add_simple_tag(simple_tag->GetTagName(),
412*103e46e4SHarish Mahendrakar simple_tag->GetTagString());
413*103e46e4SHarish Mahendrakar }
414*103e46e4SHarish Mahendrakar }
415*103e46e4SHarish Mahendrakar }
416*103e46e4SHarish Mahendrakar
417*103e46e4SHarish Mahendrakar // Set Tracks element attributes
418*103e46e4SHarish Mahendrakar const mkvparser::Tracks* const parser_tracks = parser_segment->GetTracks();
419*103e46e4SHarish Mahendrakar unsigned long i = 0;
420*103e46e4SHarish Mahendrakar uint64_t vid_track = 0; // no track added
421*103e46e4SHarish Mahendrakar uint64_t aud_track = 0; // no track added
422*103e46e4SHarish Mahendrakar
423*103e46e4SHarish Mahendrakar using mkvparser::Track;
424*103e46e4SHarish Mahendrakar
425*103e46e4SHarish Mahendrakar while (i != parser_tracks->GetTracksCount()) {
426*103e46e4SHarish Mahendrakar unsigned long track_num = i++;
427*103e46e4SHarish Mahendrakar if (switch_tracks)
428*103e46e4SHarish Mahendrakar track_num = i % parser_tracks->GetTracksCount();
429*103e46e4SHarish Mahendrakar
430*103e46e4SHarish Mahendrakar const Track* const parser_track = parser_tracks->GetTrackByIndex(track_num);
431*103e46e4SHarish Mahendrakar
432*103e46e4SHarish Mahendrakar if (parser_track == NULL)
433*103e46e4SHarish Mahendrakar continue;
434*103e46e4SHarish Mahendrakar
435*103e46e4SHarish Mahendrakar // TODO(fgalligan): Add support for language to parser.
436*103e46e4SHarish Mahendrakar const char* const track_name = parser_track->GetNameAsUTF8();
437*103e46e4SHarish Mahendrakar
438*103e46e4SHarish Mahendrakar const long long track_type = parser_track->GetType();
439*103e46e4SHarish Mahendrakar
440*103e46e4SHarish Mahendrakar if (track_type == Track::kVideo && output_video) {
441*103e46e4SHarish Mahendrakar // Get the video track from the parser
442*103e46e4SHarish Mahendrakar const mkvparser::VideoTrack* const pVideoTrack =
443*103e46e4SHarish Mahendrakar static_cast<const mkvparser::VideoTrack*>(parser_track);
444*103e46e4SHarish Mahendrakar const long long width = pVideoTrack->GetWidth();
445*103e46e4SHarish Mahendrakar const long long height = pVideoTrack->GetHeight();
446*103e46e4SHarish Mahendrakar
447*103e46e4SHarish Mahendrakar // Add the video track to the muxer
448*103e46e4SHarish Mahendrakar vid_track = muxer_segment.AddVideoTrack(static_cast<int>(width),
449*103e46e4SHarish Mahendrakar static_cast<int>(height),
450*103e46e4SHarish Mahendrakar video_track_number);
451*103e46e4SHarish Mahendrakar if (!vid_track) {
452*103e46e4SHarish Mahendrakar printf("\n Could not add video track.\n");
453*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
454*103e46e4SHarish Mahendrakar }
455*103e46e4SHarish Mahendrakar
456*103e46e4SHarish Mahendrakar mkvmuxer::VideoTrack* const video = static_cast<mkvmuxer::VideoTrack*>(
457*103e46e4SHarish Mahendrakar muxer_segment.GetTrackByNumber(vid_track));
458*103e46e4SHarish Mahendrakar if (!video) {
459*103e46e4SHarish Mahendrakar printf("\n Could not get video track.\n");
460*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
461*103e46e4SHarish Mahendrakar }
462*103e46e4SHarish Mahendrakar
463*103e46e4SHarish Mahendrakar if (pVideoTrack->GetColour()) {
464*103e46e4SHarish Mahendrakar mkvmuxer::Colour muxer_colour;
465*103e46e4SHarish Mahendrakar if (!libwebm::CopyColour(*pVideoTrack->GetColour(), &muxer_colour))
466*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
467*103e46e4SHarish Mahendrakar if (!video->SetColour(muxer_colour))
468*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
469*103e46e4SHarish Mahendrakar }
470*103e46e4SHarish Mahendrakar
471*103e46e4SHarish Mahendrakar if (pVideoTrack->GetProjection() ||
472*103e46e4SHarish Mahendrakar projection_type != mkvparser::Projection::kTypeNotPresent) {
473*103e46e4SHarish Mahendrakar mkvmuxer::Projection muxer_projection;
474*103e46e4SHarish Mahendrakar const mkvparser::Projection* const parser_projection =
475*103e46e4SHarish Mahendrakar pVideoTrack->GetProjection();
476*103e46e4SHarish Mahendrakar typedef mkvmuxer::Projection::ProjectionType MuxerProjType;
477*103e46e4SHarish Mahendrakar if (parser_projection &&
478*103e46e4SHarish Mahendrakar !CopyVideoProjection(*parser_projection, &muxer_projection)) {
479*103e46e4SHarish Mahendrakar printf("\n Unable to copy video projection.\n");
480*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
481*103e46e4SHarish Mahendrakar }
482*103e46e4SHarish Mahendrakar // Override the values that came from parser if set on command line.
483*103e46e4SHarish Mahendrakar if (projection_type != mkvparser::Projection::kTypeNotPresent) {
484*103e46e4SHarish Mahendrakar muxer_projection.set_type(
485*103e46e4SHarish Mahendrakar static_cast<MuxerProjType>(projection_type));
486*103e46e4SHarish Mahendrakar if (projection_type == mkvparser::Projection::kRectangular &&
487*103e46e4SHarish Mahendrakar projection_file != NULL) {
488*103e46e4SHarish Mahendrakar printf("\n Rectangular projection must not have private data.\n");
489*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
490*103e46e4SHarish Mahendrakar } else if ((projection_type == mkvparser::Projection::kCubeMap ||
491*103e46e4SHarish Mahendrakar projection_type == mkvparser::Projection::kMesh) &&
492*103e46e4SHarish Mahendrakar projection_file == NULL) {
493*103e46e4SHarish Mahendrakar printf("\n Mesh or CubeMap projection must have private data.\n");
494*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
495*103e46e4SHarish Mahendrakar }
496*103e46e4SHarish Mahendrakar if (projection_file != NULL) {
497*103e46e4SHarish Mahendrakar std::string contents;
498*103e46e4SHarish Mahendrakar if (!libwebm::GetFileContents(projection_file, &contents) ||
499*103e46e4SHarish Mahendrakar contents.size() == 0) {
500*103e46e4SHarish Mahendrakar printf("\n Failed to read file \"%s\" or file is empty\n",
501*103e46e4SHarish Mahendrakar projection_file);
502*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
503*103e46e4SHarish Mahendrakar }
504*103e46e4SHarish Mahendrakar if (!muxer_projection.SetProjectionPrivate(
505*103e46e4SHarish Mahendrakar reinterpret_cast<uint8_t*>(&contents[0]),
506*103e46e4SHarish Mahendrakar contents.size())) {
507*103e46e4SHarish Mahendrakar printf("\n Failed to SetProjectionPrivate of length %zu.\n",
508*103e46e4SHarish Mahendrakar contents.size());
509*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
510*103e46e4SHarish Mahendrakar }
511*103e46e4SHarish Mahendrakar }
512*103e46e4SHarish Mahendrakar }
513*103e46e4SHarish Mahendrakar const float kValueNotPresent = mkvparser::Projection::kValueNotPresent;
514*103e46e4SHarish Mahendrakar if (projection_pose_yaw != kValueNotPresent)
515*103e46e4SHarish Mahendrakar muxer_projection.set_pose_yaw(projection_pose_yaw);
516*103e46e4SHarish Mahendrakar if (projection_pose_pitch != kValueNotPresent)
517*103e46e4SHarish Mahendrakar muxer_projection.set_pose_pitch(projection_pose_pitch);
518*103e46e4SHarish Mahendrakar if (projection_pose_roll != kValueNotPresent)
519*103e46e4SHarish Mahendrakar muxer_projection.set_pose_roll(projection_pose_roll);
520*103e46e4SHarish Mahendrakar
521*103e46e4SHarish Mahendrakar if (!video->SetProjection(muxer_projection))
522*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
523*103e46e4SHarish Mahendrakar }
524*103e46e4SHarish Mahendrakar
525*103e46e4SHarish Mahendrakar if (track_name)
526*103e46e4SHarish Mahendrakar video->set_name(track_name);
527*103e46e4SHarish Mahendrakar
528*103e46e4SHarish Mahendrakar video->set_codec_id(pVideoTrack->GetCodecId());
529*103e46e4SHarish Mahendrakar
530*103e46e4SHarish Mahendrakar if (display_width > 0)
531*103e46e4SHarish Mahendrakar video->set_display_width(display_width);
532*103e46e4SHarish Mahendrakar if (display_height > 0)
533*103e46e4SHarish Mahendrakar video->set_display_height(display_height);
534*103e46e4SHarish Mahendrakar if (pixel_width > 0)
535*103e46e4SHarish Mahendrakar video->set_pixel_width(pixel_width);
536*103e46e4SHarish Mahendrakar if (pixel_height > 0)
537*103e46e4SHarish Mahendrakar video->set_pixel_height(pixel_height);
538*103e46e4SHarish Mahendrakar if (stereo_mode > 0)
539*103e46e4SHarish Mahendrakar video->SetStereoMode(stereo_mode);
540*103e46e4SHarish Mahendrakar
541*103e46e4SHarish Mahendrakar const double rate = pVideoTrack->GetFrameRate();
542*103e46e4SHarish Mahendrakar if (rate > 0.0) {
543*103e46e4SHarish Mahendrakar video->set_frame_rate(rate);
544*103e46e4SHarish Mahendrakar }
545*103e46e4SHarish Mahendrakar
546*103e46e4SHarish Mahendrakar size_t parser_private_size;
547*103e46e4SHarish Mahendrakar const unsigned char* const parser_private_data =
548*103e46e4SHarish Mahendrakar pVideoTrack->GetCodecPrivate(parser_private_size);
549*103e46e4SHarish Mahendrakar
550*103e46e4SHarish Mahendrakar if (!strcmp(video->codec_id(), mkvmuxer::Tracks::kAv1CodecId)) {
551*103e46e4SHarish Mahendrakar if (parser_private_data == NULL || parser_private_size == 0) {
552*103e46e4SHarish Mahendrakar printf("AV1 input track has no CodecPrivate. %s is invalid.", input);
553*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
554*103e46e4SHarish Mahendrakar }
555*103e46e4SHarish Mahendrakar }
556*103e46e4SHarish Mahendrakar
557*103e46e4SHarish Mahendrakar if (!strcmp(video->codec_id(), mkvmuxer::Tracks::kVp9CodecId) &&
558*103e46e4SHarish Mahendrakar (vp9_profile >= 0 || vp9_level >= 0)) {
559*103e46e4SHarish Mahendrakar const int kMaxVp9PrivateSize = 6;
560*103e46e4SHarish Mahendrakar unsigned char vp9_private_data[kMaxVp9PrivateSize];
561*103e46e4SHarish Mahendrakar int vp9_private_size = 0;
562*103e46e4SHarish Mahendrakar if (vp9_profile >= 0) {
563*103e46e4SHarish Mahendrakar if (vp9_profile < 0 || vp9_profile > 3) {
564*103e46e4SHarish Mahendrakar printf("\n VP9 profile(%d) is not valid.\n", vp9_profile);
565*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
566*103e46e4SHarish Mahendrakar }
567*103e46e4SHarish Mahendrakar const uint8_t kVp9ProfileId = 1;
568*103e46e4SHarish Mahendrakar const uint8_t kVp9ProfileIdLength = 1;
569*103e46e4SHarish Mahendrakar vp9_private_data[vp9_private_size++] = kVp9ProfileId;
570*103e46e4SHarish Mahendrakar vp9_private_data[vp9_private_size++] = kVp9ProfileIdLength;
571*103e46e4SHarish Mahendrakar vp9_private_data[vp9_private_size++] = vp9_profile;
572*103e46e4SHarish Mahendrakar }
573*103e46e4SHarish Mahendrakar
574*103e46e4SHarish Mahendrakar if (vp9_level >= 0) {
575*103e46e4SHarish Mahendrakar const int kNumLevels = 14;
576*103e46e4SHarish Mahendrakar const int levels[kNumLevels] = {10, 11, 20, 21, 30, 31, 40,
577*103e46e4SHarish Mahendrakar 41, 50, 51, 52, 60, 61, 62};
578*103e46e4SHarish Mahendrakar bool level_is_valid = false;
579*103e46e4SHarish Mahendrakar for (int i = 0; i < kNumLevels; ++i) {
580*103e46e4SHarish Mahendrakar if (vp9_level == levels[i]) {
581*103e46e4SHarish Mahendrakar level_is_valid = true;
582*103e46e4SHarish Mahendrakar break;
583*103e46e4SHarish Mahendrakar }
584*103e46e4SHarish Mahendrakar }
585*103e46e4SHarish Mahendrakar if (!level_is_valid) {
586*103e46e4SHarish Mahendrakar printf("\n VP9 level(%d) is not valid.\n", vp9_level);
587*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
588*103e46e4SHarish Mahendrakar }
589*103e46e4SHarish Mahendrakar const uint8_t kVp9LevelId = 2;
590*103e46e4SHarish Mahendrakar const uint8_t kVp9LevelIdLength = 1;
591*103e46e4SHarish Mahendrakar vp9_private_data[vp9_private_size++] = kVp9LevelId;
592*103e46e4SHarish Mahendrakar vp9_private_data[vp9_private_size++] = kVp9LevelIdLength;
593*103e46e4SHarish Mahendrakar vp9_private_data[vp9_private_size++] = vp9_level;
594*103e46e4SHarish Mahendrakar }
595*103e46e4SHarish Mahendrakar if (!video->SetCodecPrivate(vp9_private_data, vp9_private_size)) {
596*103e46e4SHarish Mahendrakar printf("\n Could not add video private data.\n");
597*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
598*103e46e4SHarish Mahendrakar }
599*103e46e4SHarish Mahendrakar } else if (parser_private_data && parser_private_size > 0) {
600*103e46e4SHarish Mahendrakar if (!video->SetCodecPrivate(parser_private_data, parser_private_size)) {
601*103e46e4SHarish Mahendrakar printf("\n Could not add video private data.\n");
602*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
603*103e46e4SHarish Mahendrakar }
604*103e46e4SHarish Mahendrakar }
605*103e46e4SHarish Mahendrakar } else if (track_type == Track::kAudio && output_audio) {
606*103e46e4SHarish Mahendrakar // Get the audio track from the parser
607*103e46e4SHarish Mahendrakar const mkvparser::AudioTrack* const pAudioTrack =
608*103e46e4SHarish Mahendrakar static_cast<const mkvparser::AudioTrack*>(parser_track);
609*103e46e4SHarish Mahendrakar const long long channels = pAudioTrack->GetChannels();
610*103e46e4SHarish Mahendrakar const double sample_rate = pAudioTrack->GetSamplingRate();
611*103e46e4SHarish Mahendrakar
612*103e46e4SHarish Mahendrakar // Add the audio track to the muxer
613*103e46e4SHarish Mahendrakar aud_track = muxer_segment.AddAudioTrack(static_cast<int>(sample_rate),
614*103e46e4SHarish Mahendrakar static_cast<int>(channels),
615*103e46e4SHarish Mahendrakar audio_track_number);
616*103e46e4SHarish Mahendrakar if (!aud_track) {
617*103e46e4SHarish Mahendrakar printf("\n Could not add audio track.\n");
618*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
619*103e46e4SHarish Mahendrakar }
620*103e46e4SHarish Mahendrakar
621*103e46e4SHarish Mahendrakar mkvmuxer::AudioTrack* const audio = static_cast<mkvmuxer::AudioTrack*>(
622*103e46e4SHarish Mahendrakar muxer_segment.GetTrackByNumber(aud_track));
623*103e46e4SHarish Mahendrakar if (!audio) {
624*103e46e4SHarish Mahendrakar printf("\n Could not get audio track.\n");
625*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
626*103e46e4SHarish Mahendrakar }
627*103e46e4SHarish Mahendrakar
628*103e46e4SHarish Mahendrakar if (track_name)
629*103e46e4SHarish Mahendrakar audio->set_name(track_name);
630*103e46e4SHarish Mahendrakar
631*103e46e4SHarish Mahendrakar audio->set_codec_id(pAudioTrack->GetCodecId());
632*103e46e4SHarish Mahendrakar
633*103e46e4SHarish Mahendrakar size_t private_size;
634*103e46e4SHarish Mahendrakar const unsigned char* const private_data =
635*103e46e4SHarish Mahendrakar pAudioTrack->GetCodecPrivate(private_size);
636*103e46e4SHarish Mahendrakar if (private_size > 0) {
637*103e46e4SHarish Mahendrakar if (!audio->SetCodecPrivate(private_data, private_size)) {
638*103e46e4SHarish Mahendrakar printf("\n Could not add audio private data.\n");
639*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
640*103e46e4SHarish Mahendrakar }
641*103e46e4SHarish Mahendrakar }
642*103e46e4SHarish Mahendrakar
643*103e46e4SHarish Mahendrakar const long long bit_depth = pAudioTrack->GetBitDepth();
644*103e46e4SHarish Mahendrakar if (bit_depth > 0)
645*103e46e4SHarish Mahendrakar audio->set_bit_depth(bit_depth);
646*103e46e4SHarish Mahendrakar
647*103e46e4SHarish Mahendrakar if (pAudioTrack->GetCodecDelay())
648*103e46e4SHarish Mahendrakar audio->set_codec_delay(pAudioTrack->GetCodecDelay());
649*103e46e4SHarish Mahendrakar if (pAudioTrack->GetSeekPreRoll())
650*103e46e4SHarish Mahendrakar audio->set_seek_pre_roll(pAudioTrack->GetSeekPreRoll());
651*103e46e4SHarish Mahendrakar }
652*103e46e4SHarish Mahendrakar }
653*103e46e4SHarish Mahendrakar
654*103e46e4SHarish Mahendrakar // We have created all the video and audio tracks. If any WebVTT
655*103e46e4SHarish Mahendrakar // files were specified as command-line args, then parse them and
656*103e46e4SHarish Mahendrakar // add a track to the output file corresponding to each metadata
657*103e46e4SHarish Mahendrakar // input file.
658*103e46e4SHarish Mahendrakar
659*103e46e4SHarish Mahendrakar SampleMuxerMetadata metadata;
660*103e46e4SHarish Mahendrakar
661*103e46e4SHarish Mahendrakar if (!metadata.Init(&muxer_segment)) {
662*103e46e4SHarish Mahendrakar printf("\n Could not initialize metadata cache.\n");
663*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
664*103e46e4SHarish Mahendrakar }
665*103e46e4SHarish Mahendrakar
666*103e46e4SHarish Mahendrakar if (!LoadMetadataFiles(metadata_files, &metadata))
667*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
668*103e46e4SHarish Mahendrakar
669*103e46e4SHarish Mahendrakar if (!metadata.AddChapters())
670*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
671*103e46e4SHarish Mahendrakar
672*103e46e4SHarish Mahendrakar // Set Cues element attributes
673*103e46e4SHarish Mahendrakar mkvmuxer::Cues* const cues = muxer_segment.GetCues();
674*103e46e4SHarish Mahendrakar cues->set_output_block_number(output_cues_block_number);
675*103e46e4SHarish Mahendrakar if (cues_on_video_track && vid_track)
676*103e46e4SHarish Mahendrakar muxer_segment.CuesTrack(vid_track);
677*103e46e4SHarish Mahendrakar if (cues_on_audio_track && aud_track)
678*103e46e4SHarish Mahendrakar muxer_segment.CuesTrack(aud_track);
679*103e46e4SHarish Mahendrakar
680*103e46e4SHarish Mahendrakar // Write clusters
681*103e46e4SHarish Mahendrakar unsigned char* data = NULL;
682*103e46e4SHarish Mahendrakar long data_len = 0;
683*103e46e4SHarish Mahendrakar
684*103e46e4SHarish Mahendrakar const mkvparser::Cluster* cluster = parser_segment->GetFirst();
685*103e46e4SHarish Mahendrakar
686*103e46e4SHarish Mahendrakar while (cluster != NULL && !cluster->EOS()) {
687*103e46e4SHarish Mahendrakar const mkvparser::BlockEntry* block_entry;
688*103e46e4SHarish Mahendrakar
689*103e46e4SHarish Mahendrakar long status = cluster->GetFirst(block_entry);
690*103e46e4SHarish Mahendrakar
691*103e46e4SHarish Mahendrakar if (status) {
692*103e46e4SHarish Mahendrakar printf("\n Could not get first block of cluster.\n");
693*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
694*103e46e4SHarish Mahendrakar }
695*103e46e4SHarish Mahendrakar
696*103e46e4SHarish Mahendrakar while (block_entry != NULL && !block_entry->EOS()) {
697*103e46e4SHarish Mahendrakar const mkvparser::Block* const block = block_entry->GetBlock();
698*103e46e4SHarish Mahendrakar const long long trackNum = block->GetTrackNumber();
699*103e46e4SHarish Mahendrakar const mkvparser::Track* const parser_track =
700*103e46e4SHarish Mahendrakar parser_tracks->GetTrackByNumber(static_cast<unsigned long>(trackNum));
701*103e46e4SHarish Mahendrakar
702*103e46e4SHarish Mahendrakar // When |parser_track| is NULL, it means that the track number in the
703*103e46e4SHarish Mahendrakar // Block is invalid (i.e.) the was no TrackEntry corresponding to the
704*103e46e4SHarish Mahendrakar // track number. So we reject the file.
705*103e46e4SHarish Mahendrakar if (!parser_track) {
706*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
707*103e46e4SHarish Mahendrakar }
708*103e46e4SHarish Mahendrakar
709*103e46e4SHarish Mahendrakar const long long track_type = parser_track->GetType();
710*103e46e4SHarish Mahendrakar const long long time_ns = block->GetTime(cluster);
711*103e46e4SHarish Mahendrakar
712*103e46e4SHarish Mahendrakar // Flush any metadata frames to the output file, before we write
713*103e46e4SHarish Mahendrakar // the current block.
714*103e46e4SHarish Mahendrakar if (!metadata.Write(time_ns))
715*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
716*103e46e4SHarish Mahendrakar
717*103e46e4SHarish Mahendrakar if ((track_type == Track::kAudio && output_audio) ||
718*103e46e4SHarish Mahendrakar (track_type == Track::kVideo && output_video)) {
719*103e46e4SHarish Mahendrakar const int frame_count = block->GetFrameCount();
720*103e46e4SHarish Mahendrakar
721*103e46e4SHarish Mahendrakar for (int i = 0; i < frame_count; ++i) {
722*103e46e4SHarish Mahendrakar const mkvparser::Block::Frame& frame = block->GetFrame(i);
723*103e46e4SHarish Mahendrakar
724*103e46e4SHarish Mahendrakar if (frame.len > data_len) {
725*103e46e4SHarish Mahendrakar delete[] data;
726*103e46e4SHarish Mahendrakar data = new unsigned char[frame.len];
727*103e46e4SHarish Mahendrakar if (!data)
728*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
729*103e46e4SHarish Mahendrakar data_len = frame.len;
730*103e46e4SHarish Mahendrakar }
731*103e46e4SHarish Mahendrakar
732*103e46e4SHarish Mahendrakar if (frame.Read(&reader, data))
733*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
734*103e46e4SHarish Mahendrakar
735*103e46e4SHarish Mahendrakar mkvmuxer::Frame muxer_frame;
736*103e46e4SHarish Mahendrakar if (!muxer_frame.Init(data, frame.len))
737*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
738*103e46e4SHarish Mahendrakar muxer_frame.set_track_number(track_type == Track::kAudio ? aud_track
739*103e46e4SHarish Mahendrakar : vid_track);
740*103e46e4SHarish Mahendrakar if (block->GetDiscardPadding())
741*103e46e4SHarish Mahendrakar muxer_frame.set_discard_padding(block->GetDiscardPadding());
742*103e46e4SHarish Mahendrakar muxer_frame.set_timestamp(time_ns);
743*103e46e4SHarish Mahendrakar muxer_frame.set_is_key(block->IsKey());
744*103e46e4SHarish Mahendrakar if (!muxer_segment.AddGenericFrame(&muxer_frame)) {
745*103e46e4SHarish Mahendrakar printf("\n Could not add frame.\n");
746*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
747*103e46e4SHarish Mahendrakar }
748*103e46e4SHarish Mahendrakar }
749*103e46e4SHarish Mahendrakar }
750*103e46e4SHarish Mahendrakar
751*103e46e4SHarish Mahendrakar status = cluster->GetNext(block_entry, block_entry);
752*103e46e4SHarish Mahendrakar
753*103e46e4SHarish Mahendrakar if (status) {
754*103e46e4SHarish Mahendrakar printf("\n Could not get next block of cluster.\n");
755*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
756*103e46e4SHarish Mahendrakar }
757*103e46e4SHarish Mahendrakar }
758*103e46e4SHarish Mahendrakar
759*103e46e4SHarish Mahendrakar cluster = parser_segment->GetNext(cluster);
760*103e46e4SHarish Mahendrakar }
761*103e46e4SHarish Mahendrakar
762*103e46e4SHarish Mahendrakar // We have exhausted all video and audio frames in the input file.
763*103e46e4SHarish Mahendrakar // Flush any remaining metadata frames to the output file.
764*103e46e4SHarish Mahendrakar if (!metadata.Write(-1))
765*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
766*103e46e4SHarish Mahendrakar
767*103e46e4SHarish Mahendrakar if (copy_input_duration) {
768*103e46e4SHarish Mahendrakar const double input_duration =
769*103e46e4SHarish Mahendrakar static_cast<double>(segment_info->GetDuration()) / timeCodeScale;
770*103e46e4SHarish Mahendrakar muxer_segment.set_duration(input_duration);
771*103e46e4SHarish Mahendrakar }
772*103e46e4SHarish Mahendrakar
773*103e46e4SHarish Mahendrakar if (!muxer_segment.Finalize()) {
774*103e46e4SHarish Mahendrakar printf("Finalization of segment failed.\n");
775*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
776*103e46e4SHarish Mahendrakar }
777*103e46e4SHarish Mahendrakar
778*103e46e4SHarish Mahendrakar reader.Close();
779*103e46e4SHarish Mahendrakar writer.Close();
780*103e46e4SHarish Mahendrakar
781*103e46e4SHarish Mahendrakar if (cues_before_clusters) {
782*103e46e4SHarish Mahendrakar if (reader.Open(temp_file.c_str())) {
783*103e46e4SHarish Mahendrakar printf("\n Filename is invalid or error while opening.\n");
784*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
785*103e46e4SHarish Mahendrakar }
786*103e46e4SHarish Mahendrakar if (!writer.Open(output)) {
787*103e46e4SHarish Mahendrakar printf("\n Filename is invalid or error while opening.\n");
788*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
789*103e46e4SHarish Mahendrakar }
790*103e46e4SHarish Mahendrakar if (!muxer_segment.CopyAndMoveCuesBeforeClusters(&reader, &writer)) {
791*103e46e4SHarish Mahendrakar printf("\n Unable to copy and move cues before clusters.\n");
792*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
793*103e46e4SHarish Mahendrakar }
794*103e46e4SHarish Mahendrakar reader.Close();
795*103e46e4SHarish Mahendrakar writer.Close();
796*103e46e4SHarish Mahendrakar remove(temp_file.c_str());
797*103e46e4SHarish Mahendrakar }
798*103e46e4SHarish Mahendrakar
799*103e46e4SHarish Mahendrakar delete[] data;
800*103e46e4SHarish Mahendrakar
801*103e46e4SHarish Mahendrakar return EXIT_SUCCESS;
802*103e46e4SHarish Mahendrakar }
803