Renamed packager_main to single_packager.
Did some re-factoring to share code with upcoming (multi stream) packager. Change-Id: I2b3845e48ba6aa63a95ecc276abcb52c8355d8d5
This commit is contained in:
parent
beaea71946
commit
7fe5b5171a
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
//
|
||||||
|
// Defines command line flags for fixed key encryption.
|
||||||
|
|
||||||
|
#include "app/fixed_key_encryption_flags.h"
|
||||||
|
|
||||||
|
DEFINE_bool(enable_fixed_key_encryption,
|
||||||
|
false,
|
||||||
|
"Enable encryption with fixed key.");
|
||||||
|
DEFINE_string(key_id, "", "Key id in hex string format.");
|
||||||
|
DEFINE_string(key, "", "Key in hex string format.");
|
||||||
|
DEFINE_string(pssh, "", "PSSH in hex string format.");
|
||||||
|
|
||||||
|
static bool IsNotEmptyWithFixedKeyEncryption(const char* flag_name,
|
||||||
|
const std::string& flag_value) {
|
||||||
|
return FLAGS_enable_fixed_key_encryption ? !flag_value.empty() : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dummy_key_id_validator =
|
||||||
|
google::RegisterFlagValidator(&FLAGS_key_id,
|
||||||
|
&IsNotEmptyWithFixedKeyEncryption);
|
||||||
|
static bool dummy_key_validator =
|
||||||
|
google::RegisterFlagValidator(&FLAGS_key,
|
||||||
|
&IsNotEmptyWithFixedKeyEncryption);
|
||||||
|
static bool dummy_pssh_validator =
|
||||||
|
google::RegisterFlagValidator(&FLAGS_pssh,
|
||||||
|
&IsNotEmptyWithFixedKeyEncryption);
|
|
@ -11,26 +11,9 @@
|
||||||
|
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
DEFINE_bool(enable_fixed_key_encryption,
|
DECLARE_bool(enable_fixed_key_encryption);
|
||||||
false,
|
DECLARE_string(key_id);
|
||||||
"Enable encryption with fixed key.");
|
DECLARE_string(key);
|
||||||
DEFINE_string(key_id, "", "Key id in hex string format.");
|
DECLARE_string(pssh);
|
||||||
DEFINE_string(key, "", "Key in hex string format.");
|
|
||||||
DEFINE_string(pssh, "", "PSSH in hex string format.");
|
|
||||||
|
|
||||||
static bool IsNotEmptyWithFixedKeyEncryption(const char* flag_name,
|
|
||||||
const std::string& flag_value) {
|
|
||||||
return FLAGS_enable_fixed_key_encryption ? !flag_value.empty() : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool dummy_key_id_validator =
|
|
||||||
google::RegisterFlagValidator(&FLAGS_key_id,
|
|
||||||
&IsNotEmptyWithFixedKeyEncryption);
|
|
||||||
static bool dummy_key_validator =
|
|
||||||
google::RegisterFlagValidator(&FLAGS_key,
|
|
||||||
&IsNotEmptyWithFixedKeyEncryption);
|
|
||||||
static bool dummy_pssh_validator =
|
|
||||||
google::RegisterFlagValidator(&FLAGS_pssh,
|
|
||||||
&IsNotEmptyWithFixedKeyEncryption);
|
|
||||||
|
|
||||||
#endif // APP_FIXED_KEY_ENCRYPTION_FLAGS_H_
|
#endif // APP_FIXED_KEY_ENCRYPTION_FLAGS_H_
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
//
|
||||||
|
// Defines Muxer flags.
|
||||||
|
|
||||||
|
#include "app/muxer_flags.h"
|
||||||
|
|
||||||
|
DEFINE_double(clear_lead,
|
||||||
|
10.0,
|
||||||
|
"Clear lead in seconds if encryption is enabled.");
|
||||||
|
|
||||||
|
DEFINE_bool(single_segment,
|
||||||
|
true,
|
||||||
|
"Generate a single segment for the media presentation. This option "
|
||||||
|
"should be set for on demand profile.");
|
||||||
|
DEFINE_double(segment_duration,
|
||||||
|
10.0f,
|
||||||
|
"Segment duration in seconds. If single_segment is specified, "
|
||||||
|
"this parameter sets the duration of a subsegment; otherwise, "
|
||||||
|
"this parameter sets the duration of a segment. Actual segment "
|
||||||
|
"durations may not be exactly as requested.");
|
||||||
|
DEFINE_bool(segment_sap_aligned,
|
||||||
|
true,
|
||||||
|
"Force segments to begin with stream access points.");
|
||||||
|
DEFINE_double(fragment_duration,
|
||||||
|
2.0f,
|
||||||
|
"Fragment duration in seconds. Should not be larger than "
|
||||||
|
"the segment duration. Actual fragment durations may not be "
|
||||||
|
"exactly as requested.");
|
||||||
|
DEFINE_bool(fragment_sap_aligned,
|
||||||
|
true,
|
||||||
|
"Force fragments to begin with stream access points. This flag "
|
||||||
|
"implies segment_sap_aligned.");
|
||||||
|
DEFINE_bool(normalize_presentation_timestamp,
|
||||||
|
true,
|
||||||
|
"Set to true to normalize the presentation timestamps to start"
|
||||||
|
"from zero.");
|
||||||
|
DEFINE_int32(num_subsegments_per_sidx,
|
||||||
|
1,
|
||||||
|
"For ISO BMFF only. Set the number of subsegments in each "
|
||||||
|
"SIDX box. If 0, a single SIDX box is used per segment; if "
|
||||||
|
"-1, no SIDX box is used; Otherwise, the muxer packs N "
|
||||||
|
"subsegments in the root SIDX of the segment, with "
|
||||||
|
"segment_duration/N/fragment_duration fragments per "
|
||||||
|
"subsegment.");
|
||||||
|
DEFINE_string(temp_dir,
|
||||||
|
"",
|
||||||
|
"Specify a directory in which to store temporary (intermediate) "
|
||||||
|
" files. Used only if single_segment=true.");
|
||||||
|
|
||||||
|
// Flags for MuxerListener.
|
||||||
|
DEFINE_bool(output_media_info,
|
||||||
|
true,
|
||||||
|
"Create a human readable format of MediaInfo. The output file name "
|
||||||
|
"will be the name specified by output flag, suffixed with "
|
||||||
|
"'.media_info'.");
|
||||||
|
DEFINE_string(scheme_id_uri,
|
||||||
|
"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",
|
||||||
|
"This flag only applies if output_media_info is true. This value "
|
||||||
|
"will be set in MediaInfo if the stream is encrypted. "
|
||||||
|
"If the stream is encrypted, MPD requires a <ContentProtection> "
|
||||||
|
"element which requires the schemeIdUri attribute. "
|
||||||
|
"Default value is Widevine PSSH system ID, and it is valid only "
|
||||||
|
"for ISO BMFF.");
|
|
@ -11,80 +11,19 @@
|
||||||
|
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
DEFINE_string(stream,
|
DECLARE_double(clear_lead);
|
||||||
"video",
|
|
||||||
"Add the specified stream to muxer. Allowed values, 'video' - "
|
|
||||||
"the first video stream; or 'audio' - the first audio stream; or "
|
|
||||||
"zero based stream id.");
|
|
||||||
DEFINE_double(clear_lead,
|
|
||||||
10.0,
|
|
||||||
"Clear lead in seconds if encryption is enabled.");
|
|
||||||
|
|
||||||
DEFINE_bool(single_segment,
|
DECLARE_bool(single_segment);
|
||||||
true,
|
DECLARE_double(segment_duration);
|
||||||
"Generate a single segment for the media presentation. This option "
|
DECLARE_bool(segment_sap_aligned);
|
||||||
"should be set for on demand profile.");
|
DECLARE_double(fragment_duration);
|
||||||
DEFINE_double(segment_duration,
|
DECLARE_bool(fragment_sap_aligned);
|
||||||
10.0f,
|
DECLARE_bool(normalize_presentation_timestamp);
|
||||||
"Segment duration in seconds. If single_segment is specified, "
|
DECLARE_int32(num_subsegments_per_sidx);
|
||||||
"this parameter sets the duration of a subsegment; otherwise, "
|
DECLARE_string(temp_dir);
|
||||||
"this parameter sets the duration of a segment. Actual segment "
|
|
||||||
"durations may not be exactly as requested.");
|
|
||||||
DEFINE_bool(segment_sap_aligned,
|
|
||||||
true,
|
|
||||||
"Force segments to begin with stream access points.");
|
|
||||||
DEFINE_double(fragment_duration,
|
|
||||||
2.0f,
|
|
||||||
"Fragment duration in seconds. Should not be larger than "
|
|
||||||
"the segment duration. Actual fragment durations may not be "
|
|
||||||
"exactly as requested.");
|
|
||||||
DEFINE_bool(fragment_sap_aligned,
|
|
||||||
true,
|
|
||||||
"Force fragments to begin with stream access points. This flag "
|
|
||||||
"implies segment_sap_aligned.");
|
|
||||||
DEFINE_bool(normalize_presentation_timestamp,
|
|
||||||
true,
|
|
||||||
"Set to true to normalize the presentation timestamps to start"
|
|
||||||
"from zero.");
|
|
||||||
DEFINE_int32(num_subsegments_per_sidx,
|
|
||||||
1,
|
|
||||||
"For ISO BMFF only. Set the number of subsegments in each "
|
|
||||||
"SIDX box. If 0, a single SIDX box is used per segment; if "
|
|
||||||
"-1, no SIDX box is used; Otherwise, the muxer packs N "
|
|
||||||
"subsegments in the root SIDX of the segment, with "
|
|
||||||
"segment_duration/N/fragment_duration fragments per "
|
|
||||||
"subsegment.");
|
|
||||||
DEFINE_string(output,
|
|
||||||
"",
|
|
||||||
"Output file path. If segment_template is not specified, "
|
|
||||||
"the muxer generates this single output file with all "
|
|
||||||
"segments concatenated; Otherwise, it specifies the "
|
|
||||||
"initialization segment name.");
|
|
||||||
DEFINE_string(segment_template,
|
|
||||||
"",
|
|
||||||
"Output segment name pattern for generated segments. It "
|
|
||||||
"can furthermore be configured using a subset of "
|
|
||||||
"SegmentTemplate identifiers: $Number$, $Bandwidth$ and "
|
|
||||||
"$Time$.");
|
|
||||||
DEFINE_string(temp_file,
|
|
||||||
"",
|
|
||||||
"Specify a temporary file for on demand media file creation. If "
|
|
||||||
"not specified, a new file will be created in an OS-dependent "
|
|
||||||
"temporary directory.");
|
|
||||||
|
|
||||||
// Flags for MuxerListener.
|
// Flags for MuxerListener.
|
||||||
DEFINE_bool(output_media_info,
|
DECLARE_bool(output_media_info);
|
||||||
true,
|
DECLARE_string(scheme_id_uri);
|
||||||
"Create a human readable format of MediaInfo. The output file name "
|
|
||||||
"will be the name specified by output flag, suffixed with "
|
|
||||||
"'.media_info'.");
|
|
||||||
DEFINE_string(scheme_id_uri,
|
|
||||||
"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",
|
|
||||||
"This flag only applies if output_media_info is true. This value "
|
|
||||||
"will be set in MediaInfo if the stream is encrypted. "
|
|
||||||
"If the stream is encrypted, MPD requires a <ContentProtection> "
|
|
||||||
"element which requires the schemeIdUri attribute. "
|
|
||||||
"Default value is Widevine PSSH system ID, and it is valid only "
|
|
||||||
"for ISO BMFF.");
|
|
||||||
|
|
||||||
#endif // APP_MUXER_FLAGS_H_
|
#endif // APP_MUXER_FLAGS_H_
|
||||||
|
|
|
@ -10,27 +10,18 @@
|
||||||
#include "app/fixed_key_encryption_flags.h"
|
#include "app/fixed_key_encryption_flags.h"
|
||||||
#include "app/muxer_flags.h"
|
#include "app/muxer_flags.h"
|
||||||
#include "app/widevine_encryption_flags.h"
|
#include "app/widevine_encryption_flags.h"
|
||||||
#include "base/file_util.h"
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/strings/string_number_conversions.h"
|
#include "base/strings/string_number_conversions.h"
|
||||||
#include "base/strings/stringprintf.h"
|
|
||||||
#include "media/base/demuxer.h"
|
|
||||||
#include "media/base/media_stream.h"
|
#include "media/base/media_stream.h"
|
||||||
|
#include "media/base/muxer.h"
|
||||||
#include "media/base/muxer_options.h"
|
#include "media/base/muxer_options.h"
|
||||||
#include "media/base/request_signer.h"
|
#include "media/base/request_signer.h"
|
||||||
#include "media/base/stream_info.h"
|
#include "media/base/stream_info.h"
|
||||||
#include "media/base/widevine_encryption_key_source.h"
|
#include "media/base/widevine_encryption_key_source.h"
|
||||||
#include "media/event/vod_media_info_dump_muxer_listener.h"
|
|
||||||
#include "media/file/file.h"
|
#include "media/file/file.h"
|
||||||
#include "media/file/file_closer.h"
|
|
||||||
#include "media/formats/mp4/mp4_muxer.h"
|
|
||||||
|
|
||||||
DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info.");
|
DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info.");
|
||||||
|
|
||||||
namespace {
|
|
||||||
const char kUsage[] =
|
|
||||||
"Packager driver program. Sample Usage:\n%s <input> [flags]";
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
|
@ -76,7 +67,7 @@ scoped_ptr<EncryptionKeySource> CreateEncryptionKeySource() {
|
||||||
}
|
}
|
||||||
|
|
||||||
encryption_key_source.reset(new WidevineEncryptionKeySource(
|
encryption_key_source.reset(new WidevineEncryptionKeySource(
|
||||||
FLAGS_server_url,
|
FLAGS_key_server_url,
|
||||||
FLAGS_content_id,
|
FLAGS_content_id,
|
||||||
signer.Pass(),
|
signer.Pass(),
|
||||||
FLAGS_crypto_period_duration == 0 ? kDisableKeyRotation : 0));
|
FLAGS_crypto_period_duration == 0 ? kDisableKeyRotation : 0));
|
||||||
|
@ -98,19 +89,7 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) {
|
||||||
muxer_options->normalize_presentation_timestamp =
|
muxer_options->normalize_presentation_timestamp =
|
||||||
FLAGS_normalize_presentation_timestamp;
|
FLAGS_normalize_presentation_timestamp;
|
||||||
muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
|
muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
|
||||||
muxer_options->output_file_name = FLAGS_output;
|
muxer_options->temp_dir = FLAGS_temp_dir;
|
||||||
muxer_options->segment_template = FLAGS_segment_template;
|
|
||||||
muxer_options->temp_file_name = FLAGS_temp_file;
|
|
||||||
|
|
||||||
// Create a temp file if needed.
|
|
||||||
if (muxer_options->single_segment && muxer_options->temp_file_name.empty()) {
|
|
||||||
base::FilePath path;
|
|
||||||
if (!base::CreateTemporaryFile(&path)) {
|
|
||||||
LOG(ERROR) << "Failed to create a temporary file.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
muxer_options->temp_file_name = path.value();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,20 +109,22 @@ MediaStream* FindFirstAudioStream(const std::vector<MediaStream*>& streams) {
|
||||||
return FindFirstStreamOfType(streams, kStreamAudio);
|
return FindFirstStreamOfType(streams, kStreamAudio);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddStreamToMuxer(const std::vector<MediaStream*>& streams, Muxer* muxer) {
|
bool AddStreamToMuxer(const std::vector<MediaStream*>& streams,
|
||||||
|
const std::string& stream_selector,
|
||||||
|
Muxer* muxer) {
|
||||||
DCHECK(muxer);
|
DCHECK(muxer);
|
||||||
|
|
||||||
MediaStream* stream = NULL;
|
MediaStream* stream = NULL;
|
||||||
if (FLAGS_stream == "video") {
|
if (stream_selector == "video") {
|
||||||
stream = FindFirstVideoStream(streams);
|
stream = FindFirstVideoStream(streams);
|
||||||
} else if (FLAGS_stream == "audio") {
|
} else if (stream_selector == "audio") {
|
||||||
stream = FindFirstAudioStream(streams);
|
stream = FindFirstAudioStream(streams);
|
||||||
} else {
|
} else {
|
||||||
// Expect FLAGS_stream to be a zero based stream id.
|
// Expect stream_selector to be a zero based stream id.
|
||||||
size_t stream_id;
|
size_t stream_id;
|
||||||
if (!base::StringToSizeT(FLAGS_stream, &stream_id) ||
|
if (!base::StringToSizeT(stream_selector, &stream_id) ||
|
||||||
stream_id >= streams.size()) {
|
stream_id >= streams.size()) {
|
||||||
LOG(ERROR) << "Invalid argument --stream=" << FLAGS_stream << "; "
|
LOG(ERROR) << "Invalid argument --stream=" << stream_selector << "; "
|
||||||
<< "should be 'audio', 'video', or a number within [0, "
|
<< "should be 'audio', 'video', or a number within [0, "
|
||||||
<< streams.size() - 1 << "].";
|
<< streams.size() - 1 << "].";
|
||||||
return false;
|
return false;
|
||||||
|
@ -152,93 +133,14 @@ bool AddStreamToMuxer(const std::vector<MediaStream*>& streams, Muxer* muxer) {
|
||||||
DCHECK(stream);
|
DCHECK(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This could occur only if FLAGS_stream=audio|video and the corresponding
|
// This could occur only if stream_selector=audio|video and the corresponding
|
||||||
// stream does not exist in the input.
|
// stream does not exist in the input.
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
LOG(ERROR) << "No " << FLAGS_stream << " stream found in the input.";
|
LOG(ERROR) << "No " << stream_selector << " stream found in the input.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
muxer->AddStream(stream);
|
muxer->AddStream(stream);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RunPackager(const std::string& input) {
|
|
||||||
Status status;
|
|
||||||
|
|
||||||
// Setup and initialize Demuxer.
|
|
||||||
Demuxer demuxer(input, NULL);
|
|
||||||
status = demuxer.Initialize();
|
|
||||||
if (!status.ok()) {
|
|
||||||
LOG(ERROR) << "Demuxer failed to initialize: " << status.ToString();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FLAGS_dump_stream_info)
|
|
||||||
DumpStreamInfo(demuxer.streams());
|
|
||||||
|
|
||||||
if (FLAGS_output.empty()) {
|
|
||||||
if (!FLAGS_dump_stream_info)
|
|
||||||
LOG(WARNING) << "No output specified. Exiting.";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup muxer.
|
|
||||||
MuxerOptions muxer_options;
|
|
||||||
if (!GetMuxerOptions(&muxer_options))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
scoped_ptr<Muxer> muxer(new mp4::MP4Muxer(muxer_options));
|
|
||||||
scoped_ptr<event::MuxerListener> muxer_listener;
|
|
||||||
scoped_ptr<File, FileCloser> mpd_file;
|
|
||||||
if (FLAGS_output_media_info) {
|
|
||||||
std::string output_mpd_file_name = FLAGS_output + ".media_info";
|
|
||||||
mpd_file.reset(File::Open(output_mpd_file_name.c_str(), "w"));
|
|
||||||
if (!mpd_file) {
|
|
||||||
LOG(ERROR) << "Failed to open " << output_mpd_file_name;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
scoped_ptr<event::VodMediaInfoDumpMuxerListener> media_info_muxer_listener(
|
|
||||||
new event::VodMediaInfoDumpMuxerListener(mpd_file.get()));
|
|
||||||
media_info_muxer_listener->SetContentProtectionSchemeIdUri(
|
|
||||||
FLAGS_scheme_id_uri);
|
|
||||||
muxer_listener = media_info_muxer_listener.Pass();
|
|
||||||
muxer->SetMuxerListener(muxer_listener.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!AddStreamToMuxer(demuxer.streams(), muxer.get()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
scoped_ptr<EncryptionKeySource> encryption_key_source;
|
|
||||||
if (FLAGS_enable_widevine_encryption || FLAGS_enable_fixed_key_encryption) {
|
|
||||||
encryption_key_source = CreateEncryptionKeySource();
|
|
||||||
if (!encryption_key_source)
|
|
||||||
return false;
|
|
||||||
muxer->SetEncryptionKeySource(encryption_key_source.get(),
|
|
||||||
FLAGS_max_sd_pixels,
|
|
||||||
FLAGS_clear_lead,
|
|
||||||
FLAGS_crypto_period_duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start remuxing process.
|
|
||||||
status = demuxer.Run();
|
|
||||||
if (!status.ok()) {
|
|
||||||
LOG(ERROR) << "Remuxing failed: " << status.ToString();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Packaging completed successfully.\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
google::SetUsageMessage(base::StringPrintf(kUsage, argv[0]));
|
|
||||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
|
||||||
if (argc < 2) {
|
|
||||||
google::ShowUsageWithFlags(argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return media::RunPackager(argv[1]) ? 0 : 1;
|
|
||||||
}
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
// Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
//
|
||||||
|
// Functionality common to single and multiple file packager.
|
||||||
|
|
||||||
|
#ifndef APP_PACKAGER_COMMON_H_
|
||||||
|
#define APP_PACKAGER_COMMON_H_
|
||||||
|
|
||||||
|
#include <gflags/gflags.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "base/memory/scoped_ptr.h"
|
||||||
|
|
||||||
|
DECLARE_bool(dump_stream_info);
|
||||||
|
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
class EncryptionKeySource;
|
||||||
|
class MediaInfo;
|
||||||
|
class MediaStream;
|
||||||
|
class Muxer;
|
||||||
|
class MuxerOptions;
|
||||||
|
|
||||||
|
/// Print all the stream info for the provided strings to standard output.
|
||||||
|
void DumpStreamInfo(const std::vector<MediaStream*>& streams);
|
||||||
|
|
||||||
|
/// Create EncryptionKeySource based on provided command line options.
|
||||||
|
/// @return A scoped_ptr containig a new EncryptionKeySource, or NULL if
|
||||||
|
/// encryption is not required.
|
||||||
|
scoped_ptr<EncryptionKeySource> CreateEncryptionKeySource();
|
||||||
|
|
||||||
|
/// Fill MuxerOptions members using provided command line options.
|
||||||
|
bool GetMuxerOptions(MuxerOptions* muxer_options);
|
||||||
|
|
||||||
|
/// Select and add a stream from a provided set to a muxer.
|
||||||
|
/// @param streams contains the set of MediaStreams from which to select.
|
||||||
|
/// @param stream_selector is a string containing one of the following values:
|
||||||
|
/// "audio" to select the first audio track, "video" to select the first
|
||||||
|
/// video track, or a decimal number indicating which track number to
|
||||||
|
/// select (start at "1").
|
||||||
|
/// @return true if successful, false otherwise.
|
||||||
|
bool AddStreamToMuxer(const std::vector<MediaStream*>& streams,
|
||||||
|
const std::string& stream_selector,
|
||||||
|
Muxer* muxer);
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
|
||||||
|
#endif // APP_PACKAGER_COMMON_H_
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
//
|
||||||
|
// Defines Muxer flags.
|
||||||
|
|
||||||
|
#include "app/muxer_flags.h"
|
||||||
|
|
||||||
|
DEFINE_string(stream,
|
||||||
|
"video",
|
||||||
|
"Add the specified stream to muxer. Allowed values, 'video' - "
|
||||||
|
"the first video stream; or 'audio' - the first audio stream; or "
|
||||||
|
"zero based stream id.");
|
||||||
|
DEFINE_string(output,
|
||||||
|
"",
|
||||||
|
"Output file path. If segment_template is not specified, "
|
||||||
|
"the muxer generates this single output file with all "
|
||||||
|
"segments concatenated; Otherwise, it specifies the "
|
||||||
|
"initialization segment name.");
|
||||||
|
DEFINE_string(segment_template,
|
||||||
|
"",
|
||||||
|
"Output segment name pattern for generated segments. It "
|
||||||
|
"can furthermore be configured using a subset of "
|
||||||
|
"SegmentTemplate identifiers: $Number$, $Bandwidth$ and "
|
||||||
|
"$Time$.");
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
//
|
||||||
|
// Defines Single muxer flags.
|
||||||
|
|
||||||
|
#ifndef APP_SINGLE_MUXER_FLAGS_H_
|
||||||
|
#define APP_SINGLE_MUXER_FLAGS_H_
|
||||||
|
|
||||||
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
|
DECLARE_string(stream);
|
||||||
|
DECLARE_string(output);
|
||||||
|
DECLARE_string(segment_template);
|
||||||
|
|
||||||
|
#endif // APP_SINGLE_MUXER_FLAGS_H_
|
|
@ -0,0 +1,123 @@
|
||||||
|
// Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "app/fixed_key_encryption_flags.h"
|
||||||
|
#include "app/packager_common.h"
|
||||||
|
#include "app/muxer_flags.h"
|
||||||
|
#include "app/single_muxer_flags.h"
|
||||||
|
#include "app/widevine_encryption_flags.h"
|
||||||
|
#include "base/file_util.h"
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
|
#include "media/base/demuxer.h"
|
||||||
|
#include "media/base/encryption_key_source.h"
|
||||||
|
#include "media/base/muxer_options.h"
|
||||||
|
#include "media/event/vod_media_info_dump_muxer_listener.h"
|
||||||
|
#include "media/file/file.h"
|
||||||
|
#include "media/file/file_closer.h"
|
||||||
|
#include "media/formats/mp4/mp4_muxer.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const char kUsage[] =
|
||||||
|
"Packager driver program. Sample Usage:\n%s <input> [flags]";
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
bool GetSingleMuxerOptions(MuxerOptions* muxer_options) {
|
||||||
|
DCHECK(muxer_options);
|
||||||
|
|
||||||
|
if (!GetMuxerOptions(muxer_options))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
muxer_options->output_file_name = FLAGS_output;
|
||||||
|
muxer_options->segment_template = FLAGS_segment_template;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RunPackager(const std::string& input) {
|
||||||
|
Status status;
|
||||||
|
|
||||||
|
// Setup and initialize Demuxer.
|
||||||
|
Demuxer demuxer(input, NULL);
|
||||||
|
status = demuxer.Initialize();
|
||||||
|
if (!status.ok()) {
|
||||||
|
LOG(ERROR) << "Demuxer failed to initialize: " << status.ToString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FLAGS_dump_stream_info)
|
||||||
|
DumpStreamInfo(demuxer.streams());
|
||||||
|
|
||||||
|
if (FLAGS_output.empty()) {
|
||||||
|
if (!FLAGS_dump_stream_info)
|
||||||
|
LOG(WARNING) << "No output specified. Exiting.";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup muxer.
|
||||||
|
MuxerOptions muxer_options;
|
||||||
|
if (!GetSingleMuxerOptions(&muxer_options))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
scoped_ptr<Muxer> muxer(new mp4::MP4Muxer(muxer_options));
|
||||||
|
scoped_ptr<event::MuxerListener> muxer_listener;
|
||||||
|
scoped_ptr<File, FileCloser> mpd_file;
|
||||||
|
if (FLAGS_output_media_info) {
|
||||||
|
std::string output_mpd_file_name = FLAGS_output + ".media_info";
|
||||||
|
mpd_file.reset(File::Open(output_mpd_file_name.c_str(), "w"));
|
||||||
|
if (!mpd_file) {
|
||||||
|
LOG(ERROR) << "Failed to open " << output_mpd_file_name;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_ptr<event::VodMediaInfoDumpMuxerListener> media_info_muxer_listener(
|
||||||
|
new event::VodMediaInfoDumpMuxerListener(mpd_file.get()));
|
||||||
|
media_info_muxer_listener->SetContentProtectionSchemeIdUri(
|
||||||
|
FLAGS_scheme_id_uri);
|
||||||
|
muxer_listener = media_info_muxer_listener.Pass();
|
||||||
|
muxer->SetMuxerListener(muxer_listener.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AddStreamToMuxer(demuxer.streams(), FLAGS_stream, muxer.get()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
scoped_ptr<EncryptionKeySource> encryption_key_source;
|
||||||
|
if (FLAGS_enable_widevine_encryption || FLAGS_enable_fixed_key_encryption) {
|
||||||
|
encryption_key_source = CreateEncryptionKeySource();
|
||||||
|
if (!encryption_key_source)
|
||||||
|
return false;
|
||||||
|
muxer->SetEncryptionKeySource(encryption_key_source.get(),
|
||||||
|
FLAGS_max_sd_pixels,
|
||||||
|
FLAGS_clear_lead,
|
||||||
|
FLAGS_crypto_period_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start remuxing process.
|
||||||
|
status = demuxer.Run();
|
||||||
|
if (!status.ok()) {
|
||||||
|
LOG(ERROR) << "Remuxing failed: " << status.ToString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Packaging completed successfully.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
google::SetUsageMessage(base::StringPrintf(kUsage, argv[0]));
|
||||||
|
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||||
|
if (argc < 2) {
|
||||||
|
google::ShowUsageWithFlags(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return media::RunPackager(argv[1]) ? 0 : 1;
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
// Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
//
|
||||||
|
// Defines command line flags for widevine_encryption.
|
||||||
|
|
||||||
|
#include "app/widevine_encryption_flags.h"
|
||||||
|
|
||||||
|
#include "base/strings/string_number_conversions.h"
|
||||||
|
|
||||||
|
DEFINE_bool(enable_widevine_encryption,
|
||||||
|
false,
|
||||||
|
"Enable encryption with Widevine license server/proxy. User should "
|
||||||
|
"provide either AES signing key (--aes_signing_key, "
|
||||||
|
"--aes_signing_iv) or RSA signing key (--rsa_signing_key_path).");
|
||||||
|
DEFINE_string(key_server_url, "", "Key server url.");
|
||||||
|
DEFINE_string(content_id, "", "Content Id.");
|
||||||
|
DEFINE_int32(max_sd_pixels,
|
||||||
|
768 * 576,
|
||||||
|
"If the video track has more pixels per frame than max_sd_pixels, "
|
||||||
|
"it is considered as HD, SD otherwise. Default: 768 * 576.");
|
||||||
|
DEFINE_string(signer, "", "The name of the signer.");
|
||||||
|
DEFINE_string(aes_signing_key,
|
||||||
|
"",
|
||||||
|
"AES signing key in hex string. --aes_signing_iv is required. "
|
||||||
|
"Exclusive with --rsa_signing_key_path.");
|
||||||
|
DEFINE_string(aes_signing_iv,
|
||||||
|
"",
|
||||||
|
"AES signing iv in hex string.");
|
||||||
|
DEFINE_string(rsa_signing_key_path,
|
||||||
|
"",
|
||||||
|
"Stores PKCS#1 RSA private key for request signing. Exclusive "
|
||||||
|
"with --aes_signing_key.");
|
||||||
|
DEFINE_int32(crypto_period_duration,
|
||||||
|
0,
|
||||||
|
"Crypto period duration in seconds. If it is non-zero, key "
|
||||||
|
"rotation is enabled.");
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static bool IsNotEmptyWithWidevineEncryption(const char* flag_name,
|
||||||
|
const std::string& flag_value) {
|
||||||
|
return FLAGS_enable_widevine_encryption ? !flag_value.empty() : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsPositive(const char* flag_name, int flag_value) {
|
||||||
|
return flag_value > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool VerifyAesRsaKey(const char* flag_name,
|
||||||
|
const std::string& flag_value) {
|
||||||
|
if (!FLAGS_enable_widevine_encryption)
|
||||||
|
return true;
|
||||||
|
const std::string flag_name_str = flag_name;
|
||||||
|
if (flag_name_str == "aes_signing_iv") {
|
||||||
|
if (!FLAGS_aes_signing_key.empty() && flag_value.empty()) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: --aes_signing_iv is required for --aes_signing_key.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (flag_name_str == "rsa_signing_key_path") {
|
||||||
|
if (FLAGS_aes_signing_key.empty() && flag_value.empty()) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: --aes_signing_key or --rsa_signing_key_path is "
|
||||||
|
"required.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!FLAGS_aes_signing_key.empty() && !flag_value.empty()) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: --aes_signing_key and --rsa_signing_key_path are "
|
||||||
|
"exclusive.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dummy_key_server_url_validator =
|
||||||
|
google::RegisterFlagValidator(&FLAGS_key_server_url,
|
||||||
|
&IsNotEmptyWithWidevineEncryption);
|
||||||
|
bool dummy_content_id_validator =
|
||||||
|
google::RegisterFlagValidator(&FLAGS_content_id,
|
||||||
|
&IsNotEmptyWithWidevineEncryption);
|
||||||
|
bool dummy_track_type_validator =
|
||||||
|
google::RegisterFlagValidator(&FLAGS_max_sd_pixels, &IsPositive);
|
||||||
|
bool dummy_signer_validator =
|
||||||
|
google::RegisterFlagValidator(&FLAGS_signer,
|
||||||
|
&IsNotEmptyWithWidevineEncryption);
|
||||||
|
bool dummy_aes_iv_validator =
|
||||||
|
google::RegisterFlagValidator(&FLAGS_aes_signing_iv,
|
||||||
|
&VerifyAesRsaKey);
|
||||||
|
bool dummy_rsa_key_file_validator =
|
||||||
|
google::RegisterFlagValidator(&FLAGS_rsa_signing_key_path,
|
||||||
|
&VerifyAesRsaKey);
|
||||||
|
|
||||||
|
} // anonymous namespace
|
|
@ -11,88 +11,14 @@
|
||||||
|
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
#include "base/strings/string_number_conversions.h"
|
DECLARE_bool(enable_widevine_encryption);
|
||||||
|
DECLARE_string(key_server_url);
|
||||||
|
DECLARE_string(content_id);
|
||||||
|
DECLARE_int32(max_sd_pixels);
|
||||||
|
DECLARE_string(signer);
|
||||||
|
DECLARE_string(aes_signing_key);
|
||||||
|
DECLARE_string(aes_signing_iv);
|
||||||
|
DECLARE_string(rsa_signing_key_path);
|
||||||
|
DECLARE_int32(crypto_period_duration);
|
||||||
|
|
||||||
DEFINE_bool(enable_widevine_encryption,
|
|
||||||
false,
|
|
||||||
"Enable encryption with Widevine license server/proxy. User should "
|
|
||||||
"provide either AES signing key (--aes_signing_key, "
|
|
||||||
"--aes_signing_iv) or RSA signing key (--rsa_signing_key_path).");
|
|
||||||
DEFINE_string(server_url, "", "License server url.");
|
|
||||||
DEFINE_string(content_id, "", "Content Id.");
|
|
||||||
DEFINE_int32(max_sd_pixels,
|
|
||||||
768 * 576,
|
|
||||||
"If the video track has more pixels per frame than max_sd_pixels, "
|
|
||||||
"it is considered as HD, SD otherwise. Default: 768 * 576.");
|
|
||||||
DEFINE_string(signer, "", "The name of the signer.");
|
|
||||||
DEFINE_string(aes_signing_key,
|
|
||||||
"",
|
|
||||||
"AES signing key in hex string. --aes_signing_iv is required. "
|
|
||||||
"Exclusive with --rsa_signing_key_path.");
|
|
||||||
DEFINE_string(aes_signing_iv,
|
|
||||||
"",
|
|
||||||
"AES signing iv in hex string.");
|
|
||||||
DEFINE_string(rsa_signing_key_path,
|
|
||||||
"",
|
|
||||||
"Stores PKCS#1 RSA private key for request signing. Exclusive "
|
|
||||||
"with --aes_signing_key.");
|
|
||||||
DEFINE_int32(crypto_period_duration,
|
|
||||||
0,
|
|
||||||
"Crypto period duration in seconds. If it is non-zero, key "
|
|
||||||
"rotation is enabled.");
|
|
||||||
|
|
||||||
static bool IsNotEmptyWithWidevineEncryption(const char* flag_name,
|
|
||||||
const std::string& flag_value) {
|
|
||||||
return FLAGS_enable_widevine_encryption ? !flag_value.empty() : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsPositive(const char* flag_name, int flag_value) {
|
|
||||||
return flag_value > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool VerifyAesRsaKey(const char* flag_name,
|
|
||||||
const std::string& flag_value) {
|
|
||||||
if (!FLAGS_enable_widevine_encryption)
|
|
||||||
return true;
|
|
||||||
const std::string flag_name_str = flag_name;
|
|
||||||
if (flag_name_str == "aes_signing_iv") {
|
|
||||||
if (!FLAGS_aes_signing_key.empty() && flag_value.empty()) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"ERROR: --aes_signing_iv is required for --aes_signing_key.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (flag_name_str == "rsa_signing_key_path") {
|
|
||||||
if (FLAGS_aes_signing_key.empty() && flag_value.empty()) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"ERROR: --aes_signing_key or --rsa_signing_key_path is "
|
|
||||||
"required.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!FLAGS_aes_signing_key.empty() && !flag_value.empty()) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"ERROR: --aes_signing_key and --rsa_signing_key_path are "
|
|
||||||
"exclusive.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool dummy_server_url_validator =
|
|
||||||
google::RegisterFlagValidator(&FLAGS_server_url,
|
|
||||||
&IsNotEmptyWithWidevineEncryption);
|
|
||||||
static bool dummy_content_id_validator =
|
|
||||||
google::RegisterFlagValidator(&FLAGS_content_id,
|
|
||||||
&IsNotEmptyWithWidevineEncryption);
|
|
||||||
static bool dummy_track_type_validator =
|
|
||||||
google::RegisterFlagValidator(&FLAGS_max_sd_pixels, &IsPositive);
|
|
||||||
static bool dummy_signer_validator =
|
|
||||||
google::RegisterFlagValidator(&FLAGS_signer,
|
|
||||||
&IsNotEmptyWithWidevineEncryption);
|
|
||||||
static bool dummy_aes_iv_validator =
|
|
||||||
google::RegisterFlagValidator(&FLAGS_aes_signing_iv,
|
|
||||||
&VerifyAesRsaKey);
|
|
||||||
static bool dummy_rsa_key_file_validator =
|
|
||||||
google::RegisterFlagValidator(&FLAGS_rsa_signing_key_path,
|
|
||||||
&VerifyAesRsaKey);
|
|
||||||
#endif // APP_WIDEVINE_ENCRYPTION_FLAGS_H_
|
#endif // APP_WIDEVINE_ENCRYPTION_FLAGS_H_
|
||||||
|
|
|
@ -60,8 +60,8 @@ struct MuxerOptions {
|
||||||
/// Optional.
|
/// Optional.
|
||||||
std::string segment_template;
|
std::string segment_template;
|
||||||
|
|
||||||
/// Specify the temporary file for on demand media file creation.
|
/// Specify temporary directory for intermediate files.
|
||||||
std::string temp_file_name;
|
std::string temp_dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
|
@ -117,7 +117,7 @@ void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options) {
|
||||||
muxer_options->num_subsegments_per_sidx = 0;
|
muxer_options->num_subsegments_per_sidx = 0;
|
||||||
muxer_options->output_file_name = "test_output_file_name.mp4";
|
muxer_options->output_file_name = "test_output_file_name.mp4";
|
||||||
muxer_options->segment_template.clear();
|
muxer_options->segment_template.clear();
|
||||||
muxer_options->temp_file_name.clear();
|
muxer_options->temp_dir.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpectMediaInfoEqual(const MediaInfo& expect, const MediaInfo& actual) {
|
void ExpectMediaInfoEqual(const MediaInfo& expect, const MediaInfo& actual) {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "media/formats/mp4/single_segment_segmenter.h"
|
#include "media/formats/mp4/single_segment_segmenter.h"
|
||||||
|
|
||||||
|
#include "base/file_util.h"
|
||||||
#include "media/base/buffer_writer.h"
|
#include "media/base/buffer_writer.h"
|
||||||
#include "media/base/media_stream.h"
|
#include "media/base/media_stream.h"
|
||||||
#include "media/base/muxer_options.h"
|
#include "media/base/muxer_options.h"
|
||||||
|
@ -37,11 +38,20 @@ bool SingleSegmentSegmenter::GetIndexRange(size_t* offset, size_t* size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Status SingleSegmentSegmenter::DoInitialize() {
|
Status SingleSegmentSegmenter::DoInitialize() {
|
||||||
temp_file_.reset(File::Open(options().temp_file_name.c_str(), "w"));
|
base::FilePath temp_file_path;
|
||||||
|
if (options().temp_dir.empty() ?
|
||||||
|
!base::CreateTemporaryFile(&temp_file_path) :
|
||||||
|
!base::CreateTemporaryFileInDir(base::FilePath(options().temp_dir),
|
||||||
|
&temp_file_path)) {
|
||||||
|
return Status(error::FILE_FAILURE, "Unable to create temporary file.");
|
||||||
|
}
|
||||||
|
temp_file_name_ = temp_file_path.value();
|
||||||
|
|
||||||
|
temp_file_.reset(File::Open(temp_file_name_.c_str(), "w"));
|
||||||
return temp_file_
|
return temp_file_
|
||||||
? Status::OK
|
? Status::OK
|
||||||
: Status(error::FILE_FAILURE,
|
: Status(error::FILE_FAILURE,
|
||||||
"Cannot open file to write " + options().temp_file_name);
|
"Cannot open file to write " + temp_file_name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status SingleSegmentSegmenter::DoFinalize() {
|
Status SingleSegmentSegmenter::DoFinalize() {
|
||||||
|
@ -53,7 +63,7 @@ Status SingleSegmentSegmenter::DoFinalize() {
|
||||||
// Close the temp file to prepare for reading later.
|
// Close the temp file to prepare for reading later.
|
||||||
if (!temp_file_.release()->Close()) {
|
if (!temp_file_.release()->Close()) {
|
||||||
return Status(error::FILE_FAILURE,
|
return Status(error::FILE_FAILURE,
|
||||||
"Cannot close the temp file " + options().temp_file_name);
|
"Cannot close the temp file " + temp_file_name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_ptr<File, FileCloser> file(
|
scoped_ptr<File, FileCloser> file(
|
||||||
|
@ -74,10 +84,10 @@ Status SingleSegmentSegmenter::DoFinalize() {
|
||||||
|
|
||||||
// Load the temp file and write to output file.
|
// Load the temp file and write to output file.
|
||||||
scoped_ptr<File, FileCloser> temp_file(
|
scoped_ptr<File, FileCloser> temp_file(
|
||||||
File::Open(options().temp_file_name.c_str(), "r"));
|
File::Open(temp_file_name_.c_str(), "r"));
|
||||||
if (temp_file == NULL) {
|
if (temp_file == NULL) {
|
||||||
return Status(error::FILE_FAILURE,
|
return Status(error::FILE_FAILURE,
|
||||||
"Cannot open file to read " + options().temp_file_name);
|
"Cannot open file to read " + temp_file_name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int kBufSize = 0x40000; // 256KB.
|
const int kBufSize = 0x40000; // 256KB.
|
||||||
|
@ -86,7 +96,7 @@ Status SingleSegmentSegmenter::DoFinalize() {
|
||||||
int64 size = temp_file->Read(buf.get(), kBufSize);
|
int64 size = temp_file->Read(buf.get(), kBufSize);
|
||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
return Status(error::FILE_FAILURE,
|
return Status(error::FILE_FAILURE,
|
||||||
"Failed to read file " + options().temp_file_name);
|
"Failed to read file " + temp_file_name_);
|
||||||
}
|
}
|
||||||
int64 size_written = file->Write(buf.get(), size);
|
int64 size_written = file->Write(buf.get(), size);
|
||||||
if (size_written != size) {
|
if (size_written != size) {
|
||||||
|
|
|
@ -44,6 +44,7 @@ class SingleSegmentSegmenter : public Segmenter {
|
||||||
virtual Status DoFinalizeSegment() OVERRIDE;
|
virtual Status DoFinalizeSegment() OVERRIDE;
|
||||||
|
|
||||||
scoped_ptr<SegmentIndex> vod_sidx_;
|
scoped_ptr<SegmentIndex> vod_sidx_;
|
||||||
|
std::string temp_file_name_;
|
||||||
scoped_ptr<File, FileCloser> temp_file_;
|
scoped_ptr<File, FileCloser> temp_file_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(SingleSegmentSegmenter);
|
DISALLOW_COPY_AND_ASSIGN(SingleSegmentSegmenter);
|
||||||
|
|
|
@ -140,7 +140,7 @@ MuxerOptions PackagerTestBasic::SetupOptions(const std::string& output,
|
||||||
|
|
||||||
options.output_file_name = GetFullPath(output);
|
options.output_file_name = GetFullPath(output);
|
||||||
options.segment_template = GetFullPath(kSegmentTemplate);
|
options.segment_template = GetFullPath(kSegmentTemplate);
|
||||||
options.temp_file_name = GetFullPath(output + ".temp");
|
options.temp_dir = test_directory_.value();
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
packager.gyp
11
packager.gyp
|
@ -16,12 +16,19 @@
|
||||||
},
|
},
|
||||||
'targets': [
|
'targets': [
|
||||||
{
|
{
|
||||||
'target_name': 'packager_main',
|
'target_name': 'single_packager',
|
||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
'sources': [
|
'sources': [
|
||||||
|
'app/fixed_key_encryption_flags.cc',
|
||||||
'app/fixed_key_encryption_flags.h',
|
'app/fixed_key_encryption_flags.h',
|
||||||
|
'app/packager_common.cc',
|
||||||
|
'app/packager_common.h',
|
||||||
|
'app/muxer_flags.cc',
|
||||||
'app/muxer_flags.h',
|
'app/muxer_flags.h',
|
||||||
'app/packager_main.cc',
|
'app/single_muxer_flags.cc',
|
||||||
|
'app/single_muxer_flags.h',
|
||||||
|
'app/single_packager_main.cc',
|
||||||
|
'app/widevine_encryption_flags.cc',
|
||||||
'app/widevine_encryption_flags.h',
|
'app/widevine_encryption_flags.h',
|
||||||
],
|
],
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
|
|
Loading…
Reference in New Issue